Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

PowerShell Prompt Customization Guide

Tech May 19 2

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 $PSDebugContext contains a value, the prompt displays [DBG]: prefix, indicating debugging mode: [DBG]: PS C:\ps-test>
  • Otherwise, it prefixes with PS and shows the current location: PS C:\ps-test>
  • In nested interactive sessions where $NestedPromptLevel exceeds 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.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.