PowerShell Prompt Customization Guide
Prompt Function Fundamentals
PowerShell includes a built-in prompt function that determines what displays in your console. You can override this default behavior by defining a custom prompt function in your PowerShell profile.
The basic syntax follows this pattern:
function prompt {
<# function body #>
}
A prompt function must return an object—typically a string. Keeping the output under 80 characters is recommended for optimal display.
function prompt { "Hello, World > " }
Retrieving Prompt Function Details
To examine the current prompt function, use either of these commands:
Get-Command prompt
Get-Item Function:prompt
To view the underlying script that defines the current prompt, access the ScriptBlock property:
(Get-Command prompt).ScriptBlock
(Get-Item Function:prompt).ScriptBlock
Default Prompt Behavior
PowerShell displays the default PS> prompt only when the prompt function generates an error or returns nothing. For instance, setting the function to return $null triggers this fallback behavior:
function prompt {$null}
PS>
Since PowerShell ships with a built-in prompt function, the default PS> prompt rarely appears in normal use.
Built-in Prompt Implementation
The default prompt function appears as follows:
function prompt {
"PS $($ExecutionContext.SessionState.Path.CurrentLocation)$('>' * ($NestedPromptLevel + 1)) ";
}
This function performs several checks:
- When
$PSDebugContextcontains a value, the prompt displays[DBG]:prefix, indicating debugging mode:[DBG]: PS C:\ps-test> - Otherwise, it prefixes with
PSand shows the current location:PS C:\ps-test> - In nested interactive sessions where
$NestedPromptLevelexceeds zero, double angle brackets appear:PS C:\ps-test>>>
Session-Specific Prompt Customization
To modify the prompt temporarily for your current session, simply define a new prompt function. This overrides the built-in version for that session only.
Basic Examples
Display the computer name in your prompt:
function prompt {"PS [$Env:COMPUTERNAME]> "}
Show the current date and time:
function prompt {"$(Get-Date)> "}
Combine the current path with the date:
function prompt {"$(Get-Location) $(Get-Date)> "}
Format the time and display the path:
function prompt {"[ $(Get-Date -Format 'HH:mm:ss') ] $(Get-Location) >"}
Detecting Elevated Privileges
You can modify the prompt to indicate administrative status:
function prompt {
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $currentIdentity
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
$prefix = $(if (Test-Path Variable:/PSDebugContext) { '[DBG]: ' }
elseif ($principal.IsInRole($adminRole)) { "[ADMIN]: " }
else { '' })
$location = Get-Location
$nesting = $(if ($NestedPromptLevel -ge 1) { '>>' })
"$prefix PS $location$nesting> "
}
When running with elevated privileges, this displays [ADMIN]: PS C:\Windows\system32>.
Showing Command History ID
This prompt function displays the next command's history ID:
function prompt {
$historyItems = @(Get-History)
if ($historyItems.Count -gt 0) {
$latestEntry = $historyItems[$historyItems.Count - 1]
$historyId = $latestEntry.Id
}
$nextId = $historyId + 1
$currentPath = Get-Location
"PS: $nextId $currentPath >"
}
Sample output: PS: 7 C:\Windows\system32 >
Running Get-History shows previous commands:
Id CommandLine
-- -----------
1 (Get-Item Function:prompt).ScriptBlock
2 Get-Location
3 function prompt {"PS [$Env:COMPUTERNAME]> "}
Random Color Variations
Create a prompt with randomly changing colors using Write-Host:
function prompt {
$colorIndex = Get-Random -Min 1 -Max 16
Write-Host ("PS " + $(Get-Location) + ">") -NoNewline -ForegroundColor $colorIndex
return " "
}
The return " " statement is necessary because Write-Host writes to the host but returns nothing. Without it, PowerShell would fall back to the default PS> prompt.
Profile File Configuration
Prompt functions and other customizations exist only within the current session. To preserve changes across sessions, store them in a PowerShell profile—a script that runs automatically when PowerShell starts.
Profile File Types and Locations
PowerShell supports multiple profile types scoped to users and host applications. The system executes profiles in a specific order, with later profiles able to override earlier ones.
All Users, All Hosts
- Windows:
$PSHOME\Profile.ps1 - Linux:
/opt/microsoft/powershell/7/profile.ps1 - macOS:
/usr/local/microsoft/powershell/7/profile.ps1
All Users, Current Host
- Windows:
$PSHOME\Microsoft.PowerShell_profile.ps1 - Linux:
/opt/microsoft/powershell/7/Microsoft.PowerShell_profile.ps1 - macOS:
/usr/local/microsoft/powershell/7/Microsoft.PowerShell_profile.ps1
Current User, All Hosts
- Windows:
$HOME\Documents\PowerShell\Profile.ps1 - Linux:
~/.config/powershell/profile.ps1 - macOS:
~/.config/powershell/profile.ps1
Current User, Current Host
- Windows:
$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 - Linux:
~/.config/powershell/Microsoft.PowerShell_profile.ps1 - macOS:
~/.config/powershell/Microsoft.PowerShell_profile.ps1
The CurrentUserCurrentHost profile (often called the PowerShell profile) always executes last, making it the most convenient place for personal customizations.
External hosts like Visual Studio Code support their own profiles:
- VS Code All Users:
$PSHOME\Microsoft.VSCode_profile.ps1 - VS Code Current User:
$HOME\Documents\PowerShell\Microsoft.VSCode_profile.ps1
The $PROFILE Variable
The $PROFILE automatic variable contains paths to all profile files for the current session:
$PROFILE | Select-Object *
This displays properties for each profile variant:
$PROFILE.CurrentUserCurrentHost$PROFILE.CurrentUserAllHosts$PROFILE.AllUsersCurrentHost$PROFILE.AllUsersAllHosts
Use $PROFILE directly in commands—for example, notepad $PROFILE opens the current user's profile in Notepad.
Creating Profile Files
PowerShell does not create profiles automatically. To create one, use:
if (!(Test-Path -Path $PROFILE)) {
New-Item -ItemType File -Path $PROFILE -Force
}
The if statement prevents accidentally overwriting an existing profile.
To create an All Users, All Hosts profile:
if (!(Test-Path -Path $PROFILE.AllUsersAllHosts)) {
New-Item -ItemType File -Path $PROFILE.AllUsersAllHosts -Force
}
Editing Profile Files
Open your profile in a text editor:
notepad $PROFILE
code $PROFILE # for VS Code
Open other profiles by specifying their full path or using profile properties:
notepad $PROFILE.AllUsersAllHosts
A simple time-and-path prompt for your profile:
function prompt {
"[ $(Get-Date -Format 'HH:mm:ss') ] $(Get-Location) >"
}
Reloading Profile Changes
After editing your profile, apply changes without restarting:
. $PROFILE
This dot-sourcing syntax reloads the profile script into your current session, similar to Linux's source command.
Execution Policy Considerations
If loading your profile fails with a script execution error, check your current execution policy:
Get-ExecutionPolicy
# Output: Restricted
For local script execution, modify the policy for your user scope:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Verify the change and reload:
Get-ExecutionPolicy
# Output: RemoteSigned
. $PROFILE
The profile now loads successfully, and changes persist across new sessions.
Bypassing Profile Loading
To start PowerShell without loading any profiles:
powershell -NoProfile
This is useful for testing or troubleshooting when profile customizations cause issues.
Comprehensive Profile Example
The following profile demonstrates several advanced customizations:
function prompt {
# Update terminal window title
$host.UI.RawUI.WindowTitle = "Working Directory: $pwd"
# Extract current folder name
$currentFolder = Split-Path -Path $pwd -Leaf
# Get current user information
$userIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
# Format current date and time
$timestamp = Get-Date -Format 'dddd hh:mm:ss tt'
# Check for administrative privileges
$isElevated = (New-Object Security.Principal.WindowsPrincipal(
[Security.Principal.WindowsIdentity]::GetCurrent()
)).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
# Calculate execution duration of the previous command
$lastCmd = Get-History -Count 1
if ($lastCmd) {
$duration = ($lastCmd.EndExecutionTime - $lastCmd.StartExecutionTime).TotalSeconds
}
# Format duration as appropriate units
if ($duration -ge 60) {
$timeSpan = [timespan]::fromseconds($duration)
$minutes, $seconds = ($timeSpan.ToString("mm\:ss")).Split(":")
$formattedDuration = "$minutes min $seconds sec"
} else {
$formattedDuration = "[math]::Round($duration, 2) sec"
}
# Build the prompt with colored segments
Write-Host "" -NoNewline
Write-Host $(
if ($isElevated) { 'Elevated ' } else { '' }
) -BackgroundColor DarkRed -ForegroundColor White -NoNewline
Write-Host " USER:$($userIdentity.Name.split('\')[1]) " -BackgroundColor DarkBlue -ForegroundColor White -NoNewline
if ($currentFolder -like "*:*) {
Write-Host " $currentFolder " -ForegroundColor White -BackgroundColor DarkGray -NoNewline
} else {
Write-Host " .\$currentFolder\ " -ForegroundColor White -BackgroundColor DarkGray -NoNewline
}
Write-Host " $timestamp " -ForegroundColor White
Write-Host "[$formattedDuration] " -NoNewline -ForegroundColor Green
"> "
}
This configuration provides:
- Administrative status indicator with a red background when running elevated
- Current username display with a blue background
- Current working directory highlighted in gray
- Formatted timestamp showing day, time, and AM/PM
- Command execution time displayed in green
Modify the script structure or remove sections according to your preferences. To change the initial directory when PowerShell starts, add a Set-Location command at the end of your profile.