Putting The PowerShell Window Title To Better Use
Posted on March 17, 2020
- and tagged as
- powershell
The default title for a PowerShell window is simply ‘Windows PowerShell’, and this is fine, but customising it can make things a little more convenient.
The Problem
If you’re anything like me you typically have between 3 and 33 PowerShell windows open, and this is a regular sight/annoyance.
The above screenshot is from the new Windows Terminal. If you haven’t checked it out yet you definitely should, tabbed PowerShell/cmd.exe/WSL/CloudShell windows are awesome.
Trying to remember where the window or tab you needed to go back to is one of those little annoyances we could do without. We can alleviate much of the pain by customising the title of each window or tab.
Setting the title manually
The window title can be set with $Host.UI.RawUI.WindowTitle
PS C:\> $Host.UI.RawUI.WindowTitle
Windows PowerShell
$Host.UI.RawUI.WindowTitle = "New Tile"
will set the title of the current window to “New Title”. This is scoped to the window or tab it is executed on, and does not persist after PowerShell is closed.
Making the changes easier
Nobody is going to remember, or want to for that matter, type $Host.UI.RawUI.WindowTitle
every time, so we can create a shortcut function in our PowerShell profile. Depending on the version of PowerShell you want to target, the profiles are located at the following paths:
- PowerShell 5.1:
%USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
- PowerShell 7:
%USERPROFILE%\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
If you haven’t made changes to the profiles before, you’ll need to create these files. They are nothing more than special PowerShell scripts that get executed when a PowerShell process is started. Let’s add the following:
function t([string]$Title) {
$Host.UI.RawUI.WindowTitle = $Title
}
Once we restart PowerShell, or dotsource the relevant profile file, we’ll have access to the t
function.
Our tabbed windows are now somewhat organised.
Adding a little automation
If like me you’re too lazy to manually set the title, we can add a little automation and set the title to the last command we typed which should provide enough context for us to easily return to that session. While not very descriptive, it will make it easier to differentiate one window or tab from another.
Once again we need to edit our profile file, and we need to add a prompt
function. The prompt
function is special, it’s what sets the prompt in our PowerShell window. PowerShell comes with a default prompt which we don’t want to completely overwrite, so we’ll need to add in the default function, and then add our code.
function prompt {
# Start default prompt
$(if (Test-Path variable:/PSDebugContext) { '[DBG]: ' }
else { '' }) + 'PS ' + $(Get-Location) +
$(if ($NestedPromptLevel -ge 1) { '>>' }) + '> '
# End default prompt
# Setting the title to the last entered command
if ((Get-History).Count -gt 0) {
$Host.UI.RawUI.WindowTitle = ((Get-History)[-1].CommandLine[0..25] -join '')
}
}
Displaying Script Progress
One handy thing we can do is periodically update the window title to show the progress of a long running script or command. Suppose we have an array of items we need to progress, perhaps a list of PCs to run commands on. Or a list of sequential numbers we want to print to the console. Let’s go with that.
$ExampleArray = @(1..200)
$ExampleArray | % {
Write-Host "Processing $_" # Doing some stuff...
# Start of relevant snippet
$PercentProcessed = [Math]::Round(($ExampleArray.indexOf($_) + 1) / $ExampleArray.Count * 100,0)
$Host.UI.RawUI.WindowTitle = "$PercentProcessed% Completed"
# End of relevant snippet
Start-Sleep -Milliseconds 50
}
And we get a nice auto-updating title that we can check from whatever other tab we’re currently working in. It also updates the taskbar incase the whole window is obscured or minimised.
Things Nobody Asked For
Ok, so nobody is going to do this, but I wanted to see how it would look. Instead of printing a value for our progress, we can create a progress bar using… emojs.
function Why {
$ExampleArray = @(1..200)
$Smile = [System.Char]::ConvertFromUtf32([System.Convert]::toInt32('1F603',16)) # Progress bar emoji
$Sadface = [System.Char]::ConvertFromUtf32([System.Convert]::toInt32('1F621',16)) # Progress bar emoji
$ExampleArray | % {
Write-Host "Processing $_" # Doing some stuff...
# Start of relevant snippet
$Processed = [Math]::Round(($ExampleArray.indexOf($_) + 1) / $ExampleArray.Count * 10,0)
$Remaining = 10 - $Processed
$WindowTitle = ($Smile * $Processed) + ($Sadface * $Remaining)
$Host.UI.RawUI.WindowTitle = $WindowTitle
# End of relevant snippet
Start-Sleep -Milliseconds 50
}
}