findHereOrParent
because some filesystem providers (like the registry provider) don't support
the use of -Filter
on Get-ChildItem
, which will throw.
Over the years, I've customized my prompt to maximize the information available to me while doing software development. Today it looks like this:
I also have a light variant:
There's a lot going on in the screenshots, so I'm going to put together the pieces. The information here assumes you have general familiarity with customizing your PowerShell environment (for example, editing your profile file). It also assumes you have some pre-requisites installed, like Git for Windows and Visual Studio.
You can copy/paste along as we go, but I have also provided downloadable versions at the end of the blog post.
Important Note: When saving the PowerShell files, make sure they are saved as "UTF-8 with Signature". This will ensure that PowerShell treats your file as UTF-8 and does not accidentally treat it as ANSI. Here is an example using my editor of choice, Notepad2:
In the original version of this blog post, I described a terminal program I used to use called ConEmu. I've since switched to Windows Terminal as it provides better compatibility with Windows Subsystem for Linux v2.
The prompt uses several special characters that are not part of a standard font (for example, the Git branch symbol in the posh-git banner). The prompt assumes that you have installed and are using one the Nerd Fonts; the screenshots shown here are done with the Iosevka Nerd Font.
The Windows Terminal application uses a configuration file. Hit "ctrl comma", and it will launch a text editor for you to edit the configuration file. This is the dark and light theme:
The full files (including the Ubuntu icon file that I use) are available here: https://gist.github.com/bradwilson/3b81a192a63056e310e453bc7f4c063d.
The blue portion of the prompt is Git project information, powered by posh-git. This is a PowerShell plugin that supports printing information about the Git repository referenced by the current directory. The great thing about posh-git is that it comes with a tremendous amount of flexibility when formatting the prompt output. Here is what it looks like by default:
You configure the prompt by overriding the default values in a configuration object that posh-git sets. Here are the overrides which convert that default prompt into the blue prompt you've seen above:
To use these overrides, place these lines after the Import-Module
statement that
posh-git added to your PowerShell profile. Once you restart your shell, you should see your new
customizations in place (don't worry about the path; we'll be re-styling that later on):
If you want to customize the symbols used in the prompt, the easiest way to find them is by using the Character Map application built into Windows. Just select the Nerd Font you're using while browsing characters, and you can copy them directly from this app into your profile:
When PowerShell wants to display your prompt, it executes the command prompt
. By default, this
command is provided by a "PowerShell function". Adding this to your Profile will override the default
prompt with our custom prompt (I'll break down each meaningful section afterward):
The findHereOrParent
function is used in a few of the prompt pieces (printing the versions of Go, Rust,
and the .NET SDK) so that the prompt piece will only be shown when you're in a folder of a project that uses the specific
language. The function itself is fairly straight forward: it looks for any of the given file paths (which supports
wildcards) in the current folder or any of the parent folders:
The try/catch here is because some filesystem providers may throw errors when running Get-ChildItem
(for example,
the registry provider does not support the use of -Filter
). We catch and swallow the error so that it's not shown.
Let's break this down into the individual parts of the prompt.
The first section of the prompt (red background) is where we optionally show errors that have occurred:
There are two categories of errors that might happen in PowerShell: internal errors (for example,
you try to run a command that doesn't exist), and external errors (when you run an executable, and
the return code is something other than zero). We have separate code for each kind. We reset the
$Error
array and the $LASTEXITCODE
values here when we're done.
Additionally, we detect the "special" exit code of -1073741510
(also known as
0xC000013A
) which indicates that the user pressed Ctrl+C to forcefully terminate
the application.
Next you'll see us printing out custom prompt environments:
This is used by things like the vs2022.ps1
script that we will discuss later. The
assumption is that any text you place into $PromptEnvironment
will be shown here.
We print the version of Go that's being used, but only do so when in a folder with a Go project (this
is determined by calling findHereOrParent go.mod
). The version is determined by calling
go version
and parsing the result:
We print the version of Rust that's being used, but only do so when in a folder with a Go project (this
is determined by calling findHereOrParent Cargo.toml
). The version is determined by calling
rustc --version
and parsing the result:
We print the version of the .NET SDK that's being used, but only do so when in a folder with a .NET project (this
is determined by calling findHereOrParent *.sln,*.csproj
; if you use other language types like F#
or VB.NET, you can add those file types as well). The version is determined by calling dotnet --version
;
this will track SDK versions via global.json
, falling back to the latest installed version when not overridden.
The gray box in my prompt shows your current kubectl context by calling
kubectl config current-context
:
I find it useful to know which Azure subscription is my current subscription when running
commands via az
, so I print out the name of the subscription in my prompt:
Two important notes:
...\usr\bin
). You may or may not want this whole folder on your
PATH; it contains nearly 300 executables as of the writing of this article, so you may instead
want to set a PowerShell alias to point to that single executable.
I borrowed some code from dev4sys to parse the INI file:
As we previously saw, posh-git does all the heavy lifting for figuring out the current Git status: it shows the current branch name as well as the state of the filesystem (modified files, un-tracked files, etc.). All we need to do is print the info:
The last element of the prompt is the current directory:
The location is normalized to replace your home folder with a tilde, for shorter paths.
At the end of the prompt, we print one cyan +
symbol for every level deep
you are in the directory stack (that is, for every un-popped directory you pushed using
Push-Location
, aka pushd
):
I like to know when I'm running as admin or not, and whether my current window is using PowerShell or PowerShell Core.
There is a little bit of Windows vs. Unix-ism here to determine whether you're an admin. On Windows,
we ask the current user identity whether it's in the Administrators
group or not; on
Unix-like environments, we test the user ID against 0
(meaning, you're root
).
Then when we print the prompt, we use green for (safe) non-admin users, and red for (unsafe) administrators.
The prompt text itself is either PS>
for PowerShell, or pwsh>
for
PowerShell Core (regardless of the OS that you're running on).
The final piece of the puzzle is setting the prompt environment. I have several commands which
place the shell into a special mode to be used for specific environments. For example, I have
a command called vs2022
which adds Visual Studio environment variables just as
though you'd run the Visual Studio Command Prompt, and then adds that information to the
printed prompt environment.
I use a single script which can be used for any version of Visual Studio 2017 (or later):
And then I use a few simpler commands to invoke it:
vs.ps1
is a little complex because Visual Studio 2017+ now allows you to install multiple editions
side by side. It looks to see which edition you have installed and uses the VsDevCmd.bat
to get the updated environment variables. If you have multiple editions installed, you can use
the -edition
switch to specify which environment you want. In addition, Visual Studio 2022+
is now 64-bit, so we are forced to look in both 32- and 64-bit Program Files.
The final line of the script sets the global PromptEnvironment
variable, which we use
in our custom prompt function (as shown previously).
You can download profile.ps1
and vs.ps1
(and friends) from my
GitHub gist.
I hope this quick tour through my custom prompt inspires you to make customizations of your own, based on your needs. Being able to carefully craft your prompt to be succinct and quickly glanceable can be very handy when spending significant time in your command window of choice.
Happy hacking!