some scripts to work with different Windows PowerShell profiles and to initialize a Windows PowerShell console
If you are like me, working on a couple of projects (or project versions) at the same time, it is a real hassle to go and change the PowerShell profile settings in ~\Documents\WindowsPowerShell
. So I needed a better system to do this.
My requirements are:
- When starting PowerShell from anywhere within a project, pick-up the project's profile
- When starting Powershell from outside a project, pick-up a default profile
- if I defined a default project, the profile for that project
- if I didn't, a generic profile
Also, it is not really easy to find out how to change the colors for the PowerShell console. There are an enormous amount of web-pages on this subject, lots of different methods to try. Different methods for different versions of PowerShell. I needed to find the best way for me.
My requirements are:
- Changing the colors of the PowerShell console
- Changing the font used in the PowerShell console
- Changing the window title for different projects (or project versions)
- Changing the window title and the prompt when running as 'Administrator'
- Changing the window title and the background color when working with different servers, VMs, clusters,...
An overview of the profile structure
HOME
|
|-- Documents
| |-- WindowsPowerShell
| |-- console.json
| |-- profile.ps1 # <<<<<<<<<< master profile
| | # (incl. default-master profile)
| |-- scripts
| |-- Apply-PSConsoleSettings.ps1
|
|-- Projects
|-- .psprofile.ps1 # <<<<<<<<<< default-project profile
|
|-- project-1
| |-- .psconsole.json
| |-- .psprofile.ps1 # <<<<<<<<<< project profile
| |
| |-- scripts
| |-- Apply-PSConsoleSettings.ps1
|
|-- project-2
| |-- .psconsole.json
| |-- .psprofile.ps1 # <<<<<<<<<< project profile
| |
| |-- scripts
| |-- Apply-PSConsoleSettings.ps1
.
.
.
|-- project-N
|-- .psconsole.json
|-- .psprofile.ps1 # <<<<<<<<<< project profile
|
|-- scripts
|-- Apply-PSConsoleSettings.ps1
You can find the master profile in the folder ~\Documents\WindowsPowerShell
in a file called profile.ps1
.
ℹ️
There are actually a number of profiles on your machine. We are using theCurrentUserAllHosts
profile here. For more info, see https://docs.microsoft.com/en-gb/powershell/module/microsoft.powershell.core/about/about_profiles, but documentation doesn't always seem to line-up with what we see in a PowerShell console.
If the folder or file are not there, you should create it. You can pick-up our profile from the scripts
folder in this project (@HOME-Documents-WindowsPowerShell_profile.ps1
) and rename it profile.ps1
. Remark that you may have to change the marked line at the end, pointing to the default-project profile.
⚠️
you may also need to copy the correspondingconsole.json
used by theApply-PSConsoleSettings
script in our profile. More info [here](#the-default-master profile).
We want to run a different profile depending on the current directory.
- when you open Powershell from the start menu, it will open in a default directory (usually
C:\Windows\System32
) - when you start PowerShell from a command prompt, it will open in the current directory of the Command Prompt
- when you type
powershell
in the address bar of Windows Explorer, it will open in the current Windows Explorer directory - when you start PowerShell from a
PowerShell Here
context menu, the current directory will depend on the place where you opened the menu.
Assuming you don't use the -NoProfile
option, PowerShell will always start executing the master profile.
- The master profile we are using, will look in the current directory, to see if there is a
.psprofile.ps1
file it can run. - If there is none, it will look in the first parent, grand-parent, ..., up to the user's home directory, for a
.psprofile.ps1
file it can run. - When it finds one, it will set the
$ROOT
variable to this path and run the profile found. - When it doesn't find one, it will run the default-project profile and sets the
$ROOT
variable. - If that also fails, we run the default-master profile and set the
$ROOT
variable to the home directory.
Most of my projects use a profile that's very similar to the @HOME-Projects-myproject_.profile.ps1
in the scripts
folder of this project.
- We set
$ROOT
to the project directory- if you pick-up our script, you will need to adapt the path for
$ROOT
.
- if you pick-up our script, you will need to adapt the path for
- We add the
$ROOT\scripts
folder to$env:PATH
- If we are not already somewhere under the project root-directory, we set the current directory to the project root-directory
- We apply settings to the PowerShell console (see further)
- for this, you need to copy the
Apply-PSConsoleSettings.ps1
script in thescripts
folder of this project, and put it under the$ROOT\scripts
folder in your project. - you also need to copy the
@HOME-Projects-myproject_.profile.ps1
in thescripts
folder of this project to you root folder, and rename it.psconsole.json
- for this, you need to copy the
Our project-profile looks something like
Set-Variable HOME "$env:USERPROFILE" -Scope Global -Force
( Get-PSProvider 'FileSystem' ).Home = $HOME # replace "~"
$global:ROOT = "$HOME\Projects\psconsole"
$env:PATH = "$ROOT\scripts;$env:PATH"
if ( -not ( Get-Location ).Path.StartsWith("$ROOT") ) {
Set-Location "$ROOT"
}
Apply-PSConsoleSettings "PSCONSOLE"
⚠️
The$HOME
variable doesn't always seem to correctly populated, hence we set it in this profile. We experienced a lot of issues with this on different computers and with different versions of PowerShell (probably because of a lack of understanding?). You can find more info about the$HOME
variable here: https://docs.microsoft.com/en-gb/powershell/module/microsoft.powershell.core/about/about_automatic_variables, but the documentation doesn't always seem to line-up with what we see in a PowerShell console.
- By default we use
"$env:USERPROFILE"
. Although this is in my experience the most reliable way, this variable may not be correctly set on your machine.- An alternative (this is what the PowerShell documentation states as the method it uses "automatically") is to use
"$env:HOMEDRIVE$env:HOMEPATH"
.- You can look for other variables in your environment (or add them) to help you create the correct
$HOME
variable.- You can look for solutions on the web.
- Perhaps you need to update some registry items?
- Ultimately, as a last resort, you can hard-code your home-path as a string.
💡
We copy theApply-PSConsoleSettings
to every project. This avoids issues when the script gets updated for a new project while scripts and corresponding profiles of old projects are not updated.
I like to put all my projects in a ~/Projects
folder so that is where I put my .psprofile.ps1
file, but you can put it anywhere else and give it any name you want. You can pick-up our profile from the scripts
folder in this project (@Projects_.psprofile.ps1
), rename it and adapt it.
- If you are using our master profile, update the marked line at the end of the master profile.
The job of the default-project profile is to select a default project and run its profile. In our sample default-project profile, we list all our projects in comments in the script, and uncomment the project we consider our "default" at the moment (only uncomment projects that have a project-profile). This makes it very easy to switch "default" projects.
. ~/Projects/psconsole/.psprofile.ps1
#. ~/Projects/kluster/.psprofile.ps1
#. ~/Projects/steps/.psprofile.ps1
#. ~/Projects/globals/.psprofile.ps1 #<<< !!! has no project-profile at the moment
The last section in the master-profile is the default-master profile. You can put whatever you want in there. We use something similar to the project profiles in our default-master profile
- We set
$ROOT
to the home directory - We add the
~\Documents\WindowsPowerShell\scripts
folder to$env:PATH
- If we are not already somewhere under the home directory, we set the current directory to the home directory
- We apply settings to the PowerShell console (see further)
- for this, you need to copy the
Apply-PSConsoleSettings.ps1
script in thescripts
folder of this project, and put it under the~\Documents\WindowsPowerShell\scripts
folder on your machine. - you also need to copy the
@HOME-Documents-WindowsPowerShell_console.json
file in thescripts
folder of this project to your~\Documents\WindowsPowerShell
folder, and rename itconsole.json
- for this, you need to copy the
Our default master profile looks something like
$global:ROOT = $HOME
$env:PATH = "$ROOT\Documents\WindowsPowerShell\scripts;$env:PATH"
if ( -not ( Get-Location ).Path.StartsWith("$ROOT") ) {
Set-Location "$ROOT"
}
Apply-PSConsoleSettings
There are lots of properties that can be changed, but we will focus on colors:
- The color palette used by the console
- The foreground and background colors of the console
- The colors of the output to various streams
- The colors used for syntax-highlighting
- The colors of the prompt
A couple of other properties we want to adapt
- The title of the PowerShell console window, including an indication when we are running in elevated mode
- An indication in the prompt when we are running in elevated mode
- The window size
- The font and font-size in the console
To control all of this, we use a script Apply-PSConsoleSettings.ps1
in combination with a JSON configuration file. You can find the default configuration for a project in $ROOT\.psconsole.json
.
Some of these properties cannot be changed by a script like Apply-PSConsoleSettings.ps1
, but can be changed in the registry (which we prefer not to do) or in the properties of a shortcut to PowerShell:
- The color palette used by the console
Finally, some of these properties can be both changed from within a console or in the shortcut to a console. We elected to set the following in the properties of a shortcut:
- The window size
To understand the sometimes "unexpected" results when changing colors, we need a bit more explanation to understand some of the basics of color palettes.
The color palette consists of 16 colors. Default color-values are defined in a color-table in the registry (ColorTable00
.. ColorTable15
). This can be overridden in the properties of a shortcut to PowerShell application (.lnk
file), hence colors can be different depending on how you start the console.
⚠️
If you change colors of theDefaults
, you will be changing color-table for the PowerShell application in the registry, so the new colors will apply to all instances of Powershell. If you change the colors in theProperties
, the changes are only applied to instances of PowerShell that are started via the specific shortcut where you changed the properties (overriding theDefaults
).
More info on the hierarchy of loaded settings can be found here: https://devblogs.microsoft.com/commandline/understanding-windows-console-host-settings/
- The color palette shown here is the color palette associated to the
Properties
of the shortcut in the start menu. - The colors of the color-table in the registry correspond to the colors in the
Defaults
andProperties
from left to right.
💡
The PowerShell shortcut can usually be found in the Start Menu:"$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"
(or with the(x86)
suffix for the 32-bit version).
To illustrate the difference between the color palettes when starting Powershell in different ways, below, we started the console from the Run app
- One of the immediate differences you can observe is the much less saturated yellow color of the
[Administrator]
indication in the prompt, compared to the higher screenshot.
And the corresponding color properties
- When we started PowerShell from the Run app, we started the
.exe
application, not the.lnk
shortcut on the Start Menu. This is using the default color-table forpowershell.exe
from the registry instead of the properties of a shortcut.
ℹ️
The colors or your PowerShell.exe console may be different than what's shown here. This is because the default console colors were recently changed to a dimmer version ( https://devblogs.microsoft.com/commandline/updating-the-windows-console-colors/ ), so your installation may still be using the legacy colors in the registry color-tables.
An overview
ColorTable | Foreground ANSI/VT100 | Background ANSI/VT100 | PowerShell Name | Legacy Console | New Console | PowerShell Color |
---|---|---|---|---|---|---|
ColorTable00 |
``e[30m` | ``e[40m` | Black |
(0,0,0) | (12,12,12) | - |
ColorTable01 |
``e[34m` | ``e[44m` | DarkBlue |
(0,0,128) | (0,55,128) | - |
ColorTable02 |
``e[32m` | ``e[42m` | DarkGreen |
(0,128,0) | (19,161,14) | - |
ColorTable03 |
``e[36m` | ``e[46m` | DarkCyan |
(0,128,128) | (58,150,221) | - |
ColorTable04 |
``e[31m` | ``e[41m` | DarkRed |
(128,0,0) | (197,15,31) | - |
ColorTable05 |
``e[35m` | ``e[45m` | DarkMagenta |
(128,0,128) | (136,23,152) | (1,36,86) |
ColorTable06 |
``e[33m` | ``e[43m` | DarkYellow |
(128,128,00) | (193,156,0) | (238,237,240) |
ColorTable07 |
``e[37m` | ``e[47m` | Gray (DarkWhite ) |
(192,192,192) | (204,204,204) | - |
ColorTable08 |
``e[90m` | ``e[100m` | DarkGray (LightBlack ) |
(128,128,128) | (118.118,118) | - |
ColorTable09 |
``e[94m` | ``e[104m` | Blue |
(0,0,255) | (59,120,255) | - |
ColorTable10 |
``e[92m` | ``e[102m` | Green |
(0,255,0) | (22,198,12) | - |
ColorTable11 |
``e[96m` | ``e[106m` | Cyan |
(0,255,255) | (97,214,214) | - |
ColorTable12 |
``e[91m` | ``e[101m` | Red |
(255,0,0) | (231,72,86) | - |
ColorTable13 |
``e[95m` | ``e[105m` | Magenta |
(255,0,255) | (180,0,158) | - |
ColorTable14 |
``e[93m` | ``e[103m` | Yellow |
(255,255,0) | (249,241,165) | - |
ColorTable15 |
``e[97m` | ``e[107m` | White |
(255,255,255) | (242,242,242) | - |
- The ColorTable names are the names as you will find them in the registry.
- The ANSI/VT100 codes are the codes you can use to change colors in strings. Remark that this is only works on newer versions of PowerShell. The ``e
escape code will also only work on newer versions of Powershell, but can be replace by
$e = [char]27` or `$e = [char]0x1B`. - In Powershell scripts, you don't use the names
ColorTable00
, etc... to specify colors. Instead you use:Black
,DarkBlue
, ...,White
. - The
Screen Text
andScreen Background
have been changed from the default console colors, specifically for the PowerShell console. - As written before, the default console colors have recently been redefined ( https://devblogs.microsoft.com/commandline/updating-the-windows-console-colors/ ).
- Colors you see may be completely different than what is expected from the name. For instance the links to PowerShell in the Start Menu redefine
DarkMegenta
andDarkYellow
. Also the PowerShell.lnk
shortcut in the Start Menu is using the legacy console colors, while the PowerShell.exe
application is using the new console colors.
⚠️
From Windows 10 build 1809 onward, thePSReadline
module was upgraded from version 1.2 to a 2.0.0-beta version. This beta version causes a lot of issues that cannot be worked around. To make the following work, you MUST downgrade thePSReadLine
module to version 1.2
check if you have version 2.0.0
Get-Module PSReadLine
gives
ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 2.0.0 PSReadLine {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PS...
run PowerShell as administrator, and execute
Install-Module -Name PSReadLine -RequireVersion 1.2 -SkipPublisherCheckdelete
C:\Program Files\WindowsPowerShell\Modules\PSReadline\2.0.0
check
Get-InstalledModule PSReadLine
gives
Version Name Repository Description ------- ---- ---------- ----------- 1.2 PSReadLine PSGallery Great command line editing in the Powe...
As explained in the previous section, the colors of the console are defined in the registry and in the properties of a shortcut to the PowerShell application. We don't really want to change the registry because that changes colors for every instance of the application, so we are going to focus on creating shortcuts, and change the colors of these shortcuts.
-
New-Shortcut
creates a new shortcut.New-Shortcut "$ROOT\scripts\my-powershell.lnk" -TargetPath "powershell.exe"
- remark the name of the shortcut should be the full path to the shortcut, an the extension
.lnk
is optional. - have a look at the top of the script in the
scripts
folder for more parameters, f.i.-Arguments
and-WorkingDirectory
- remark the name of the shortcut should be the full path to the shortcut, an the extension
-
Get-Shortcut
is used by the other scripts. It gets an object to modify the properties of a shortcut.ℹ️
This is the age-oldGet-Link
you find in a lot of posts on this subject. The link provided in most of these posts doesn't work anymore. Luckily, Neil Pankey (and friends) did find and preserve this code ( https://github.com/neilpa/cmd-colors-solarized/blob/master/Get-Link.ps1 ) - Thanks Neil 😌 -
Set-ShortcutColors
Set-ShortcutColors "$ROOT/playground/my-powershell.lnk" -Theme "$ROOT/colors/psconsole-powershell-legacy.json"
themes are a json file, f.i. the
psconsole-powershell-legacy.json
theme{ "console": { "ScreenTextColor": 6, "ScreenBackgroundColor": 5, "PopupTextColor": 3, "PopupBackgroundColor": 15, "ConsoleColors": [ "#000000", "#000080", "#008000", "#008080", "#800000", "#012456", "#eeedf0", "#c0c0c0", "#808080", "#0000ff", "#00ff00", "#00ffff", "#ff0000", "#ff00ff", "#ffff00", "#ffffff" ] } }
- We developed a number of color-schemes based on the very popular
Solarized
theme, but with a couple of modifications, and added more choices in background colors. You can read more on theColorized
themes here - We also added a couple based on the traditional Powershell background color.
⚠️
Remark that you need to runApply-PSConsoleSettings
in your profile with a.psconsole.json
file, to make sure that the above palette colors are correctly mapped on the colors for Powershell elements (stream output, syntax tokens and prompt). - We developed a number of color-schemes based on the very popular
-
Set-ShortcutWindowSize
sets the size of the windows and screen-bufferSet-ShortcutWindowSize "$ROOT/scripts/my-powershell.lnk" -Width 120 -Height 50 -ScreenBufferHeight 5000
-
Write-ColorizedColors
shows the colors of the color-scheme of the current shell. -
Test-ColorizedColors
creates a folder$ROOT/playground
, and in that folder a powershell-shortcut for every color-scheme.
You can see a couple more results here.
💡 We made some conversion tables to convert names between different systems.
⚠️
In the this and following sections, we will use theApply-PSConsoleSettings
script to set the colors. For this to work, you MUST copy the@HOME-Projects-myproject_.psconsole.json
file to your home directory and rename it to.psconsole.json
, AND do the same for any project folders where you want to use this script in your project-profile.
The Apply-PSConsoleSettings
is used to map palette colors on the colors of the output to the different PowerShell streams. The mapping is defined in the .psconsole.json
file in the $ROOT
folder. This file MUST have three sections:
{
"UserColorScheme": {
// ... mapping of 'Colorized' color-schemes on PowerShell elements in a normal user console
},
"AdminColorScheme": {
// ... mapping of 'Colorized' color-schemes on PowerShell elements in an administrator console
},
"LegacyColorScheme": {
// ... mapping of 'powershell-legacy' and '-campbell' color-schemes on PowerShell elements in any console
}
}
The mapping of foreground and background colors for streams is defined by properties "Stream*"
, for instance for the "LegacyColorScheme"
"StreamOutputForegroundColor": "DarkYellow",
"StreamOutputBackgroundColor": "DarkMagenta",
"StreamErrorForegroundColor": "Red",
"StreamErrorBackgroundColor": "Black",
"StreamWarningForegroundColor": "Yellow",
"StreamWarningBackgroundColor": "Black",
"StreamDebugForegroundColor": "Yellow",
"StreamDebugBackgroundColor": "Black",
"StreamVerboseForegroundColor": "Yellow",
"StreamVerboseBackgroundColor": "Black",
"StreamProgressForegroundColor": "Yellow",
"StreamProgressBackgroundColor": "DarkCyan",
The mapping of foreground and background colors for syntax-highlighting is defined by properties "Syntax*"
, for instance for the "LegacyColorScheme"
"SyntaxCommandForegroundColor": "Yellow",
"SyntaxCommandBackgroundColor": "DarkMagenta",
"SyntaxCommentForegroundColor": "DarkGreen",
"SyntaxCommentBackgroundColor": "DarkMagenta",
"SyntaxContinuationPromptForegroundColor": "DarkYellow",
"SyntaxContinuationPromptBackgroundColor": "DarkMagenta",
"SyntaxDefaultForegroundColor": "DarkYellow",
"SyntaxDefaultBackgroundColor": "DarkMagenta",
"SyntaxEmphasisForegroundColor": "Cyan",
"SyntaxEmphasisBackgroundColor": "DarkMagenta",
"SyntaxErrorForegroundColor": "Red",
"SyntaxErrorBackgroundColor": "DarkMagenta",
"SyntaxKeywordForegroundColor": "Green",
"SyntaxKeywordBackgroundColor": "DarkMagenta",
"SyntaxMemberForegroundColor": "White",
"SyntaxMemberBackgroundColor": "DarkMagenta",
"SyntaxNumberForegroundColor": "White",
"SyntaxNumberBackgroundColor": "DarkMagenta",
"SyntaxOperatorForegroundColor": "DarkGray",
"SyntaxOperatorBackgroundColor": "DarkMagenta",
"SyntaxParameterForegroundColor": "DarkGray",
"SyntaxParameterBackgroundColor": "DarkMagenta",
"SyntaxSelectionForegroundColor": "DarkMagenta",
"SyntaxSelectionBackgroundColor": "DarkYellow",
"SyntaxStringForegroundColor": "DarkCyan",
"SyntaxStringBackgroundColor": "DarkMagenta",
"SyntaxTypeForegroundColor": "Gray",
"SyntaxTypeBackgroundColor": "DarkMagenta",
"SyntaxVariableForegroundColor": "Green",
"SyntaxVariableBackgroundColor": "DarkMagenta",
The mapping of foreground and background colors for the prompt is defined by properties "Prompt*"
, for instance for the "LegacyColorScheme"
"PromptForegroundColor": "DarkYellow",
"PromptBackgroundColor": "DarkMagenta"
⚠️
In this section, we will use theApply-PSConsoleSettings
script to set the window title and the prompt. For this to work, you MUST copy the@HOME-Projects-myproject_.psconsole.json
file to your home directory and rename it to.psconsole.json
, AND do the same for any project folders where you want to use this script in your project-profile.
To add the project name to the window title - for instance "PSCONSOLE"
Apply-PSConsoleSettings "PSCONSOLE"
This gives
- remark that the color of the prompt is also dimmed - this will be discussed below.
When running PowerShell as an administrator, an indication of this is added to title and prompt
If you don't like what we did with the prompt, you can disable the changes to the prompt
Apply-PSConsoleSettings "PSCONSOLE" -NoPrompt
⚠️
In this section, we will use theApply-PSConsoleSettings
script to set the font and font-size. For this to work, you MUST copy the@HOME-Projects-myproject_.psconsole.json
file to your home directory and rename it to.psconsole.json
, AND do the same for any project folders where you want to use this script in your project-profile.
The font settings are defined in the .psconsole.json
file in the $ROOT
folder. This file MAY have:
{
"Font": "Lucida Console",
"FontSize": 14
}
"Lucida Console"
is the default value for the font, 14
is the default value for the font-size.
💡
The available fonts are specified in the registry under 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont'. If the font you want is not there, you can add it, but there are limitations on the fonts that can be added.
- Monitor evolution of the
PSReadLine
version 2.0.0 module