Tiny tweaks for PowerShell perfection

Use these tips to customize PowerShell and make it even more efficient.
258 readers like this.
open source button on keyboard


I'm in love with PowerShell. It's the perfect blend of feature-richness and readability in scripting (power) and laconism in the command line (shell). But a rant on the cross-platform open-source awesomeness of PowerShell is best saved for another article (which I've already written and which you must read if you want your life to have meant something).

Once you've accepted PowerShell into your heart and onto your laptop, the tips in this article can help you tweak PowerShell just the way you like, for hours upon hours of PowerShelling delight.

Configuring startup settings

Bash users will be familiar with the .bashrc or .bash_profile file, which contains commands that run each time a shell instance starts up. PowerShell has a similar file, though its location is system-specific. The full path of that file is available in the $profile variable in PowerShell. If you wish to make use of any or all of the tweaks described below, simply place them into this file.

Ding-dong, the ding is dead

If you run PowerShell on Windows (don't worry, we won't judge), you might run into a small auditory nuisance: if you press Backspace in an empty prompt, you may hear an annoying bell-type sound. You can turn it off with this command:

Set-PSReadlineOption -BellStyle None

Take a tab at Windows

Tab completion is one of PowerShell's most amazing features. When you type a portion of a cmdlet or a parameter on Linux or MacOS and then press Tab, PowerShell will show you all the possible completions of the cmdlet or parameter you typed. You can even type just the name of a cmdlet followed by a hyphen, then press Tab to see all the parameters quickly:

PS /home/yevster/Documents/ArticlesInProgress> Get-Command -                    
Name                  ArgumentList          InformationAction                   
Verb                  All                   ErrorVariable                       
Noun                  ListImported          WarningVariable                     
Module                ParameterName         InformationVariable                 
FullyQualifiedModule  ParameterType         OutVariable                         
CommandType           Verbose               OutBuffer                           
TotalCount            Debug                 PipelineVariable                    
Syntax                ErrorAction                                               
ShowCommandInfo       WarningAction     

Unfortunately, the default behavior on Windows is different. When you type a part of a cmdlet or a parameter on Windows, PowerShell will provide just the first available completion. You can then press Tab again (and again and again) to cycle through the other completions. Yuck!

Fortunately, fixing this abomination takes much less time than describing it did. Just add this line to your $profile:

Set-PSReadlineOption -EditMode Emacs

The blight on white

If you have configured your terminal to use black text on a white background, you may run into ugliness when using PowerShell:

powershell white on white

Although PowerShell inherits the parent terminal's colors for background and foreground, it independently colorizes specific tokens on the command line. For example, by default object members and numbers are colored white, which makes them hard to see on a white background.

Fortunately, this problem is easy to fix by sticking this little gem into your $profile:

$colorScheme = @{
    None      = "Black";
    Comment   = "DarkMagenta";
    Keyword   = "DarkGreen"; 
    String    = "DarkBlue";
    Operator  = "DarkRed";
    Variable  = "DarkGreen";
    Command   = "DarkRed";
    Parameter = "DarkGreen";
    Type      = "DarkGray";
    Number    = "DarkGray";
    Member    = "DarkGray";

$colorScheme.Keys | % { Set-PSReadlineOption -TokenKind $_ -ForegroundColor $colorScheme[$_] }

Feel free to tweak the $colorScheme map above to your liking (as if you need my permission). You can see all the available color options by typing [ConsoleColor].GetEnumNames().

Make it prompt

You can customize the PowerShell prompt to display whatever you want: the time, your username, insults about your coworkers. To customize the prompt, all you need to do is define a function named prompt. The string that this function returns will be your PowerShell prompt.

Here's how my prompt normally looks:

07:10PM /home/yevster>

I say "normally" because I added a nifty little tweak: When a command (or a cmdlet) exits with an error status, I've rigged PowerShell to let me know:

powershell error

Seeing the return status can be helpful when, as in the example above, messages written to standard error are balefully suppressed.

Here's how I configured my PowerShell prompt in my $profile (and so can you):

function prompt {
	$lastResult = Invoke-Expression '$?'
	if (!$lastResult) {
		Write-Host "Last command exited with error status." -ForegroundColor Red
	Write-Output "${msg}$(
		# Show time as 12:05PM
		Get-Date -UFormat "%I:%M%p"
		# Show current directory
	) $(Get-Location)> "  

The key is in the chords

PowerShell offers oodles of ways to minimize typing. Tab completion is one. Aliases are another. Here's one more: You can configure PowerShell to execute a specific script block in response to a key combination (chord) of your choice.

Let's imagine I am a social media addict and want to make it easy to check Facebook compulsively. I would add this line to my $profile:

Set-PSReadlineKeyHandler -Chord Ctrl+F -ScriptBlock { google-chrome https://www.facebook.com } 

It's up to you to ensure the chord you specify isn't already used by your terminal application. If it is, the key combination may not get relayed to PowerShell.

Here's a more productive use of the chord binding functionality: Committing changes to Git and pushing them to the remote repository origin with one swift key combo:

Set-PSReadlineKeyHandler -Chord Ctrl+G -ScriptBlock {
	$message = Read-Host "Please enter a commit message"
	/usr/bin/git commit -m "$message" | Write-Host
	$branch = (/usr/bin/git rev-parse --abbrev-ref HEAD)
	Write-Host "Pushing ${branch} to remote"
	/usr/bin/git push origin $branch | Write-Host

Note: Standard output of any command launched via a key chord will not be displayed in the terminal. If you do want to see output from a command in the terminal, pipe it to the Write-Host CMDlet, as I did in the example above.

All's well that ends

Since you have braved my heinous puns to get this far, I hope you have in the process made your PowerShell even more enjoyable to use. If you have any favorite hacks that I've missed, I'd love to see them. Please comment and/or tweet me.

Happy PowerShelling!

User profile image.
Software Engineer, with an open source governance bend. Occasional developer outreacher. All opinions are my own. Brain droppings here.


Is PowerShell open source?

Thanks for the post. :)

It's comforting to know that you can finally have a decent shell in Windows. When I installed Win10 on a VM, it was already there, I didn't have to go looking for it.

Thanks - it would be useful if you include detail on the best way to create $profile and 'fix' it so that it will run on login.

Great article. The few times I've needed to work with PS were quite
frustrating, and this covers most of my frustrations.

I'm surprised you didn't mention the built in IDE, powershell_ise.
I definitely preferthis to notepad, the default program for ps1 files.

For now I'll stick with bash in Ubuntu on Windows 10 via WSL, but thanks for proselytizing. I'll keep it in mind.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.