- Use PowerShell splatting and PSBoundParameters to pass parameters - Wed, Nov 9 2022
- Using PowerShell with $PSStyle - Mon, Jan 24 2022
- Clean up user profiles with PowerShell - Mon, Jun 9 2014
For some time now, we've been able to use ANSI escape sequences in a PowerShell session. You've seen this when tying a command at a console prompt. Commands, parameters, strings, and operators are displayed in color. These colors are defined as PSReadline options.
The ANSI sequences begin with an escape, which is [Char]0x1b or [Char]27. In PowerShell 7, we can use `e. The ANSI sequence follows the escape. This entire sequence precedes the string you wish to treat. You typically close the sequence with a reset command, $([char]27)[0m.
You can also use ANSI to bold or underline.
Not only is this fun, but it can also add value to PowerShell output. To make this easier to use, Microsoft introduced a new feature in PowerShell 7.2 called PSStyle.
$PSStyle
As far as I can see, there are no cmdlets for this feature. Everything you need is wrapped up in a new variable called $PSStyle.
The ANSI values are shown in their rendered colors.
Important
It is very important to note that if you are running PowerShell in Windows Terminal, you will get different interpretations based on your color scheme.
Use these values in place of the actual ANSI sequence.
"`nRunning $($psstyle.Background.Blue)PowerShell$($psstyle.Reset)$($psstyle.Reset) $($psstyle.Foreground.Yellow)v{0}$($psstyle.Reset) on $($psstyle.Foreground.BrightCyan){1}$($psstyle.Reset)." -f $($psversiontable.PSVersion),(Get-CimInstance win32_operatingsystem).caption
I may have gone a bit overboard here, and I think there is a legitimate debate as to whether this is easier than using the actual ANSI sequences. But it works.
You might use this to color part of your prompt. Or maybe to add emphasis to a warning message.
$msg = "Could not find part of path: {0}{1}{2}{3}" -f $psstyle.Italic,$psstyle.Background.Cyan,"c:\work",$psstyle.Reset Write-Warning $msg
In this example, I'm combining styles.
Customizing style
The foreground and background color values are read-only. However, the $PSStyle object has a method you can use to set a foreground or background color from a set of RGB values.
"$($PSStyle.Foreground.FromRgb(0,200,100))I am the walrus$($PSStyle.Reset)"
I'm more likely to create and assign the new value to a variable.
$custom = $PSStyle.Foreground.FromRgb(0,200,100) "$($custom)I am the walrus$($PSStyle.Reset)"
But there's much more to PSStyle.
Format rendering
In PowerShell 7.2, you'll notice that formatted tables have a little style.
Where did those green column headings come from?
You can modify these values instead of changing values in $host.privatedata, as we did in previous versions of PowerShell. I'll change the error color.
$PSStyle.Formatting.Error = "`e[38;5;201m"
You'll notice that the error message is displayed in red, which is the value in $host.privatedata. However, when I look at the error with Get-Error, the formatted result uses my new PSStyle setting.
Here's a change to warnings.
Or change the table headers.
$psstyle.Formatting.TableHeader = "`e[3;38;5;195m"
If you want to revert to plain-text tables, you can change the rendering setting.
$psstyle.OutputRendering = "Plaintext"
However, this will disable all ANSI-related settings. To change it back, set the value to "ANSI".
Be aware that any changes to $PSStyle are not persistent unless you add them to your PowerShell profile script.
By the way, if you are wondering where I got the ANSI sequences, I used the Show-ANSISequence command from the PSScriptTools module, which you can install from the PowerShell Gallery.
Progress style
One of the big changes in PowerShell 7.2 is how progress bars are displayed. The new format is more Linux-like and command line-friendly. It also doesn't add as much overhead as the previous progress displays. Settings for the new progress style are configured here.
Now, when you run a command that uses Write-Progress, you'll get something like this.
The command above is also from the PSScriptTools module.
If you need or prefer the legacy look, you can easily set that.
$psstyle.Progress.view = "Classic"
Use a value of 'Minimal' for the new style. Or feel free to adjust the color.
$psstyle.Progress.Style = "`e[38;5;123m"
Here's some silly sample code to see this in action.
1..100 | ForEach-Object -Begin {$i= 0} -process { $i++ $p = ($i/100)*100 Write-progress -Activity "Demo" -CurrentOperation "Processing $_" -Status "Square = $($_*$_)" -PercentComplete $p Start-Sleep -Milliseconds 100 }
One potential drawback of this new style is that it appears that the CurrentOperation line is left out.
File Info
I've saved the best part for last. You can use $PSStyle to format directory listings.
However, if you do a directory listing, you probably won't recognize any difference. To take advantage of this feature, you need to enable an experimental feature.
Enable-ExperimentalFeature PSANSIRenderingFileInfo
You'll see a message about restarting PowerShell. Unlike changes to values in $PSStyle, this change is persistent until you disable the feature. But look at the difference.
It might be hard to detect the color of PS1 files. No problem. I can change that.
$psstyle.FileInfo.Extension[".ps1"] = "`e[38;5;123m"
You can't change what Windows detects as an executable here, but you can add a file extension.
$PSStyle.FileInfo.Extension.add(".xml","`e[38;5;190m")
It isn't that difficult to define a style for a group of file extensions.
$ext =".gif",".bmp",".png",".jpg",".jpeg" foreach ($e in $ext) { $PSStyle.FileInfo.Extension.add($e,"`e[38;5;111m") }
Since I've been having so much fun with this, I realized I needed a good way to configure my FileInfo settings without having to constantly be editing a profile script. I wrote a set of PowerShell functions, one to export FileInfo settings to a JSON file and another to import them. You can find the functions online here. Save the PS1 file to your desktop, and dot source it.
Once you've configured your FileInfo settings, export them to a JSON file.
Export-PSStyleFileInfo C:\work\fileinfo.json
In your PowerShell profile script, dot source the PS1 file and then import the settings.
Import-PSStyleFileInfo c:\work\fileinfo.json
Summary
I'm very excited to see how I can incorporate PSStyle into my everyday PowerShell work and scripting. Remember, this requires PowerShell 7.2, so if you haven't updated, this might be a good reason to do so. And if you find a great use case for these settings, I'd love to hear about it.
As always very detailed and interestingly written. Thanks a lot!
I found out that using an array with |out-file causes undesirable characters in the file which when used by another script will break your script. I had posted this issue on github and the guys were nice enough to let me know about wrapping that statement in the $psstyle.outputrendering command.
I tried using the $psstyle.OutputRendering = “Plaintext” at the begining of my script to avoid having to wrap every statement that wants to output an array to a file. seems to be working so far.
Hi Jeff
Thank you for this article and the PSStyle functions.
For the directory listings I’ve been using Get-ChildItemColor and also Terminal-Icons, which adds icons. Both of those work in WindowsPowerShell as well.
I’m a little concerned modules will start fighting eachother and that it becomes harder and harder to find where a setting or an issue comes from.
What’s your advice on keeping this all manageable? Do you uninstall potential conflicting modules?
Hopefully, the module name makes it clear what it might do. You might import the modules in your PowerShell profile script and include a comment about what the module or command will be doing. How you manage conflicts might depend on whether it is something that is part of your interactive session or when running a script. In a script, you could always test for the conflicting module, remove it from the session, run your code, then re-import it. Or maybe the conflict is an indication that you don’t need both modules, and one has to go. There is no straight and straightforward answer to this question.