How to Write Colorized Text with PowerShell

Are you building PowerShell automation scripts that display information about your IT environment? Do you wish that you could change text or background colors, in your terminal, to any color that you wanted to? If the answer is yes, then read on!

PowerShell Core edition has built-in support for ANSI escape codes. ANSI escape codes can be used for a variety of purposes, but one of the more common examples is outputting colorized text. Colorized text is actually outputted using a Control Sequence Introducer (CSI). All this means it that your escape sequence should start with ESC[ instead of just ESC by itself. There’s a specific type of CSI called the Select Graphic Rendition (SGR), which is how you can change the color of your text (foreground color) or background color.

Why would I colorize text?

You can use colorized text to indicate different meanings in your PowerShell scripts and applications. Consider some of the following scenarios, where colors can help the user of your application to understand intent.

  • Systems Monitoring – red text indicates a problem, green text indicates an “okay” state
  • Stock Prices – red indicates a decrease in stock price, green indicates increase in stock price
  • Gaming – an explosion could be drawn using ASCII characters in orange-reddish gradient
  • PowerShell Prompt – you can colorize text inside your custom PowerShell prompt, using ANSI escape codes

There are nearly infinite other use cases where you might want to use custom text colors. Use your creativity to help drive development of your PowerShell scripts! You’re not stuck with simply having White text on a dark background!

Setting Foreground Text Color with 24-bit Color

If you’d like to set the foreground color of your text using 24-bit color (8 bits each for red, green, blue), you will want to use the ESC[38;2;r;g;bmHello SGR parameter. The r, g, and b are placeholders for the actual values, ranging from 0 to 255 (8 bit integer), for each color.

Any time you see an article reference the ANSI ESC character, you can refer to it by using `e in your PowerShell strings. Also, it’s very important that you use double-quotes to surround your strings with ANSI escape codes, otherwise they will not be interpreted correctly!

Here’s an example:

"`e[38;2;255;0;0mThis is red and `e[38;2;0;255;0mgreen and `e[38;2;0;0;255mblue!"

As you can see, each time that we emit a new ANSI escape code, the foreground (text) color changes! While the syntax can look confusing to newcomers, once you practice with it enough, it’ll become second nature.

Setting Background Color with ANSI Escape Codes

Setting the terminal background color is just as easy as setting the foreground color. The only difference is that you want to use the 48 CSI code instead of 38.

"`e[48;2;0;100;0mThis has a green background"

Resetting Terminal Color State with SGR Parameters

Once you’ve used a CSI inside your string, you’ll need to revert the changes so that newly printed text is not affected. If you forget to reset your environment, you’ll probably end up with colorized text or background colors where you didn’t expect it. The CSI code to reset your SGR parameters is ESC[0m;.

Here’s an example of writing some colored text, followed by some text in the terminal’s default text color. Give it a try yourself, and see what the output looks like!

"`e[38;2;255;0;0mHello`e[0m Trevor!"

Another scenario where resetting your SGR parameter is important, is if you’re calling an external utility that colorizes some text, but doesn’t reset it for you. Hence, it’s probably a good idea to use the reset SGR parameter any time that you are writing out text that you expect to look “normal,” using the default foreground and background colors of your terminal application.

For example, see the following screenshot where the first character of my prompt function is being drawn as a dark color instead of the default (White). This is happening, because my prompt function is not explicitly resetting the SGR parameters before printing out the first character of the prompt. To fix this, I would need to modify my prompt function to include the SGR reset parameter, just before printing the first opening square bracket character.

Reverse Foreground and Background Color

Another SGR control code allows you to simply reverse the current foreground and background colors. This is useful in scenarios where you’re drawing a status bar in an application, or perhaps selecting an item from a list. Instead of using 38 or 48, we’ll use 7 to reverse, and 27 to un-reverse colors.

Consider the following example:

"`e[7mThis is reversed"

Notice how, just as with foreground and background colors, the custom settings stick around until they’re explicitly shut off. Now, you might not want to perform a full SGR “reset” operation, as that would wipe out your custom colors. Instead, you can simply “undo” the color reversal operation, by using SGR code 27.

"`e[7mThis is reversed and`e[27m this is not reversed!"

This example shows how we can use a custom foreground / text color, in conjunction with the SGR reversal code. We start out by setting a foreground color of red, then swap the colors so our background is now red, and then we undo the reversal. Using the `e[27m code allows us to disable the color reversal, without resetting all of our SGR settings.

"`e[38;2;255;0;0mThis text is red and `e[7mThis background is red`e[27m but this is not."

How did you make your header image?

I crafted up a PowerShell script that generated the picture in the header of this blog post. If you’re interested in generating it yourself, check out the code below. It’s fairly simplistic, but basically we’re grabbing the buffer size and dynamically setting a color depending on which column number it is. I’ll leave it to you to reverse engineer the code and learn from it.

function Set-Cursor {
    [CmdletBinding()]
    param ([int] $x, [int] $y)
    $Host.UI.RawUI.CursorPosition = @{x=$x;y=$y}
}

function Get-Character {
    [CmdletBinding()]
    param ([int]$index)
    $mystring = '                   Trevor Sullivan'
    return $index -ge ($mystring.Length) ? ' ' : $mystring[$index]
}

function main {

    for ($y = 0; $y -le ($host.ui.RawUI.BufferSize.Height-1); $y++) {
        $Color = 25
        Set-Cursor -x $PSItem -y $y
        0..($Host.UI.RawUI.BufferSize.Width-1) | % { 
            Write-Host -Object ("`e[48;2;0;0;$Color`m{0}" -f (Get-Character -Index $PSItem)) -NoNewline
            $Color += 2
        }
    }
    Start-Sleep -Seconds 5
}

main

Call to Action

Now that you understand how to use ANSI escape codes in PowerShell, I encourage you to play around with this SGR setting and customize some of your text colors in your existing scripts! Next time you write a new script, you can think about how to integrate these escape sequences into them from the ground up.

Although this article focuses on setting foreground and background colors, there are some other SGR parameters as well. For example, you can underline text, make text blink (yeah, retro!), and in some cases, even use italicized text.