Published in Articles on by Michiel van Oosterhout ~ 4 min read
This is the third article in a series of articles that aims to ultimately reproduce the custom Bash prompt in Windows Command Processor. After creating the Color extension, and making sure we can reliably output Powerline symbols, we are now ready to recreate the Prompt extension to print colorful prompt mockups in Windows Command Processor.
Segmented prompt
We will be using the Powerline symbols found in the Cascadia Mono PL font we installed earlier to separate segments and sub-segments. We'll emit the Unicode code points into a script using UTF-8 encoding, and we'll use the Color extension to achieve the desired effect of a segmented prompt.
The Prompt extension for Windows Command Processor
The Windows PowerShell script below creates the Prompt extension. This extension simplifies the printing of prompt mockups.
# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando\Prompt"
$_ = New-Item $path -Force -ItemType Directory
# Declare the dividers
$E0B0 = [char]0xE0B0
$E0B1 = [char]0xE0B1
# Declare the script contents
$script = @"
@echo off
setlocal enabledelayedexpansion
rem The prompt string
set output=
rem A string holding a segment separator
set sep=
rem Initially the 'previous' background color is the terminal background color
set prev_bg=-
rem Initially there was no previous segment and thus no previous sub-segment
set prev_segment=false
set prev_sub_segment=false
rem This acts as if the previous arg was a separator (e.g '/')
set start_segment=true
rem Counts sub-segments
set count=0
rem Loop over all parameters
:continue
set p=%~1
if "%p%"=="" (
goto :done
)
rem Handle separator
if "%p%"=="/" (
rem This signals the next iteration to interpret %p% as colors
set start_segment=true
rem Restart counting sub-segments
set count=0
rem Continue with next parameter
shift && goto :continue
)
rem Handle colors
if "%start_segment%"=="true" (
rem Interpret %p% as colors
set bg=%p:~0,1%
set fg=%p:~1,1%
if "%prev_segment%"=="true" (
rem Prepare a 'connecting' separator to be rendered later
for /f %%s in ('call %CMD%\Color\color.cmd !bg!%prev_bg%') do set "sep=%%s"
set "sep=!sep!$E0B0"
for /f %%s in ('call %CMD%\Color\color.cmd !bg!!fg!') do set "sep=!sep!%%s"
)
rem Prepare for rendering sub-segments
for /f %%s in ('call %CMD%\Color\color.cmd !bg!!fg!') do set output=%output%%%s
rem Ensure the next iteration does not interpret %p% as colors
set start_segment=false
rem Ensure the next iteration does not add a sub-separator
set prev_sub_segment=false
rem Continue with next parameter
shift && goto :continue
)
rem Counting sub-segments
set /a count=%count% + 1
rem Handle sub-segments
call set evaluated=%p%
if not "%evaluated%"=="" (
if not "%sep%"=="" (
rem Render the separator
set "output=%output%%sep%"
rem Reset the separator until the next segment
set sep=
)
rem Ensure next separator will 'connect' to this segment
set prev_bg=%bg%
if "%prev_sub_segment%"=="true" (
rem Render a sub-separator
for /f %%s in ('call %CMD%\Color\color.cmd %bg%-') do set "output=%output%%%s"
set "output=!output!$E0B1"
for /f %%s in ('call %CMD%\Color\color.cmd %bg%%fg%') do set "output=!output!%%s"
)
rem Ensure the next iteration adds a sub-separator
set prev_sub_segment=true
rem Append the sub-segment with 1 space of padding
set "output=!output! %p% "
rem Ensure a separator is added eventually
set prev_segment=true
)
rem Continue with next parameter
shift && goto :continue
:done
if "%prev_segment%"=="true" (
rem Append the final separator
for /f %%s in ('call %CMD%\Color\color.cmd 0%prev_bg%') do set output=%output%%%s
set output=!output!$E0B0
for /f %%s in ('call %CMD%\Color\color.cmd 00') do set output=!output!%%s
)
rem Echo the prompt without a newline
<NUL set /p _=%output%
endlocal
"@
# Create the Windows Command Processor script
$path = "$path\prompt.cmd"
Set-Content -Encoding UTF8 -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`r`n") + "`r`n" | Set-Content -Encoding UTF8 -NoNewline $path
# Remove the BOM
$bytes = Get-Content -Encoding Byte -Path $path
[IO.File]::WriteAllBytes($path, $bytes[3..($bytes.Length - 1)])
Now we can call the function, e.g. call %CMD%\UseCp\usecp.cmd 65001 call %CMD%\Prompt\prompt.cmd bW %USERNAME% %COMPUTERNAME% / mW %CD%
, to output a colored prompt mockup with segments and sub-segments. We use the UseCp extension to ensure the code page is set to 65001
(Unicode UTF-8) for the duration of the prompt.cmd
script.

As we can see from the screenshot above, for the prompt string bY No %EMPTY% sub-segment / RW %NO% %SEGMENT% / mW %CD%
, empty (sub-)segments are not rendered.
Conclusion
The ability to quickly create a mockup of a segmented prompt is great for prototyping a custom prompt. The extension presented in this article simplifies the command for creating such a mockup, requiring only two letters to specify the colors, a space to create sub-segments, and a /
to create a new segment.
The next article will show how we can use the Prompt extension to configure a custom Bash Windows Command Processor prompt.
Updates
- Fixed
prompt.cmd
to handle parameters that contain a reference to a variable that is not set.