Published in Articles on by Michiel van Oosterhout ~ 4 min read
In this, the final article of the 3rd series of articles about command-line prompts, we'll finish the configuration of a custom Windows PowerShell prompt. At the end of this article, we will have a consistent, dynamic prompt in Git Bash, Bash in WSL, Windows Command Processor, and Windows PowerShell.
Setting the prompt
After part 1 we now have a profile that automatically sources any installed script that was tagged profile
, and we have installed one such script that contains the Get-PromptDir
, Get-GitAt
, and Set-Color
functions. All that is left is a prompt
function that will return a custom prompt if $Env:PS_PROMPT
is set.
# Get the prompt script
$path = (Get-InstalledScript -Name prompt).InstalledLocation
$path = Join-Path -Path $path -ChildPath "prompt.ps1"
# Declare the script contents
$script = @'
function Prompt
{
if (-not $Env:PS_PROMPT)
{
return "PS $($executionContext.SessionState.Path.CurrentLocation)>"
}
# Set environment variables for prompt
$Env:PROMPT_DIR = Get-PromptDir
$Env:PROMPT_GIT_AT = Get-GitAt
$expression = "Get-Prompt $Env:PS_PROMPT"
$result = Invoke-Expression $expression
return "`r`n$result "
}
function Get-Prompt
{
# The prompt string
$prompt = ""
# A string holding a segment separator
$separator = ""
# Initially the 'previous' background color is the terminal background color
$prevBg = "-"
# Initially there was no previous segment and thus no previous sub-segment
$prevSegment = $false
$prevSubSegment = $false
# This acts as if the previous arg was a separator (e.g '/')
$startSegment = $true
# Counts sub-segments
$count = 0
# Loop over all items
foreach ($item in $args)
{
# Handle separator
if ($item -eq "/")
{
# This signals the next iteration to interpret $item as colors
$startSegment = $true
# Continue with next parameter
continue
}
# Handle colors
if ($startSegment)
{
# Interpret $item as colors
$bg = $item.SubString(0, 1)
$fg = $item.SubString(1, 1)
if ($prevSegment)
{
# Prepare a 'connecting' separator to be rendered later
$separator = Set-Color "$bg$prevBg"
$separator += [char]0xE0B0
$separator += Set-Color "$bg$fg"
}
# Prepare for rendering sub-segments
$prompt += Set-Color "$bg$fg"
# Ensure the next iteration does not interpret $item as colors
$startSegment = $false
# Ensure the next iteration does not add a sub-separator
$prevSubSegment = $false
# Continue with next parameter
continue
}
# Counting sub-segments
$count = $count + 1
# Handle sub-segments
if ("$item")
{
if ($separator)
{
# Render the separator
$prompt += $separator
# Reset the separator until the next segment
$separator = ""
}
# Ensure next separator will 'connect' to this segment
$prevBg = $bg
if ($prevSubSegment)
{
# Render a sub-separator
$prompt += Set-Color "$bg-"
$prompt += [char]0xE0B1
$prompt += Set-Color "$bg$fg"
}
# Ensure the next iteration adds a sub-separator
$prevSubSegment = $true
# Append the sub-segment with 1 space of padding
$prompt += " "
$prompt += "$item"
$prompt += " "
# Ensure a separator is added eventually
$prevSegment = $true
# Continue with next parameter
continue
}
}
if ($prevSegment)
{
# Append the final separator
$prompt += Set-Color "0$prevBg"
$prompt += [char]0xE0B0
$prompt += Set-Color "00"
}
return $prompt
}
'@
# Append the script contents
Add-Content -Path $path -Value $script
The Prompt
function will return the same value as the built-in prompt
function, unless Env:PS_PROMPT
is set. Then it will first prepare any PROMPT_
environment variables that may be used in $Env:PS_PROMPT
, and then it will build the prompt string using the same logic we've seen in the Bash and Windows Command Processor incarnations.

To set $Env:PS_PROMPT
you can run cmd /c setx PS_PROMPT "bW `$Env:PROMPT_DIR / Y- `$Env:PROMPT_GIT_AT"
. Notice that you need to escape the $
to prevent the environment variables from being expanded once at the time of setting $Env:PS_PROMPT
.
Conclusion
Windows PowerShell's use of a prompt
function and its profile system makes it relatively easy to configure a custom prompt. Part of the solution presented was built using PowerShellGet's script package (namely the installation of a tagged script). As with the Windows Command Processor solution, this solution adds significant latency to the Windows PowerShell startup, but a lot less latency to the rendering of each prompt.