Published in Articles on by Michiel van Oosterhout ~ 3 min read

Using the color function we built for Bash as inspiration, let's try to achieve something similar for Windows Command Processor. We will use the Commando extension system to create a Color extension that will help us create colored output.

The Color extension for Windows Command Processor

Windows Command Processor already has a color command, used to change the background and foreground colors of the entire buffer. But we want something similar to the color function we created for Bash earlier, which only outputs the SGR terminal sequence to change the color of the output that follows it.

# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando\Color"
$_ = New-Item $path -Force -ItemType Directory

# Declare the ESC control code
$esc = [char]0x1B

# Declare the script contents
$script = @"
@echo off
setlocal enabledelayedexpansion

rem Normal colors
set colors_normal[k]=0
set colors_normal[r]=1
set colors_normal[g]=2
set colors_normal[y]=3
set colors_normal[b]=4
set colors_normal[m]=5
set colors_normal[c]=6
set colors_normal[w]=7

rem Bright colors
set colors_bright[K]=60
set colors_bright[R]=61
set colors_bright[G]=62
set colors_bright[Y]=63
set colors_bright[B]=64
set colors_bright[M]=65
set colors_bright[C]=66
set colors_bright[W]=67

rem Default background color
set colors_normal[0]=9

rem Start the SGR terminal sequence
set seq=$esc[

rem Parse background color
set bg=%1
set bg=%bg:~0,1%

if "%bg%" == "-" (
    rem Parameters for RGB color
    set seq=%seq%48;2;%TERM_BACKGROUND_COLOR%
) else if "%bg%" == "+" (
    rem Parameters for RGB color
    set seq=%seq%48;2;%TERM_FOREGROUND_COLOR%
) else (
    rem Parameter for palette-based background color
    echo %bg% | findstr [KRGYBMCW] 1>NUL
    if errorlevel 1 (
        set bg=!colors_normal[%bg%]!
    ) else (
        set bg=!colors_bright[%bg%]!
    )
    set /a bg=!bg! + 40
    set seq=%seq%!bg!
)

rem Separate the parameters for background color and foreground color
set seq=%seq%;

rem Parse foreground color
set fg=%1
set fg=%fg:~1,1%

if "%fg%" == "-" (
    rem Parameters for RGB color
    set seq=%seq%38;2;%TERM_BACKGROUND_COLOR%
) else if "%fg%" == "+" (
    rem Parameters for RGB color
    set seq=%seq%38;2;%TERM_FOREGROUND_COLOR%
) else (
    rem Parameter for palette-based background color
    echo %fg% | findstr [KRGYBMCW] 1>NUL
    if errorlevel 1 (
        set fg=!colors_normal[%fg%]!
    ) else (
        set fg=!colors_bright[%fg%]!
    )
    set /a fg=!fg! + 30
    set seq=%seq%!fg!
)

rem Finish the SGR terminal sequence
set seq=%seq%m

rem Output the SGR terminal sequence
<NUL set /p _=%seq%

endlocal
"@

# Create the Windows Command Processor script
$path = "$path\color.cmd"
Set-Content -Path $path -Value $script

The lack of true arrays and the case-insensitivity of variable names makes the Windows Command Processor version slightly longer and more complex than the Bash version. Also notice how we output the terminal sequence without a new line by using set /p to prompt for input, and redirecting from NUL to immediately provide the input.

Now we can call the function, e.g. call %CMD%\Color\color.cmd rw to set the background color to red and the foreground color to white.

Using the *Color* extension in Windows Command Processor
Using the Color extension in Windows Command Processor

Conclusion

Although not as easy to write (or read), the Windows Command Prompt scripting language can be used to create a function that renders terminal sequences for colored output.