Skip to content

Instantly share code, notes, and snippets.

Last active September 21, 2023 11:07
  • Star 69 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
PowerShell Prompt
#Requires -Version 7
# Version 1.2.13
# check if newer version
$gistUrl = ""
$latestVersionFile = [System.IO.Path]::Combine("$HOME",'.latest_profile_version')
$versionRegEx = "# Version (?<version>\d+\.\d+\.\d+)"
if ([System.IO.File]::Exists($latestVersionFile)) {
$latestVersion = [System.IO.File]::ReadAllText($latestVersionFile)
$currentProfile = [System.IO.File]::ReadAllText($profile)
[version]$currentVersion = "0.0.0"
if ($currentProfile -match $versionRegEx) {
$currentVersion = $matches.Version
if ([version]$latestVersion -gt $currentVersion) {
Write-Verbose "Your version: $currentVersion" -Verbose
Write-Verbose "New version: $latestVersion" -Verbose
$choice = Read-Host -Prompt "Found newer profile, install? (Y)"
if ($choice -eq "Y" -or $choice -eq "") {
try {
$gist = Invoke-RestMethod $gistUrl -ErrorAction Stop
$gistProfile = $gist.Files."profile.ps1".Content
Set-Content -Path $profile -Value $gistProfile
Write-Verbose "Installed newer version of profile" -Verbose
. $profile
catch {
# we can hit rate limit issue with GitHub since we're using anonymous
Write-Verbose -Verbose "Was not able to access gist, try again next time"
$global:profile_initialized = $false
function prompt {
function Initialize-Profile {
$null = Start-ThreadJob -Name "Get version of `$profile from gist" -ArgumentList $gistUrl, $latestVersionFile, $versionRegEx -ScriptBlock {
param ($gistUrl, $latestVersionFile, $versionRegEx)
try {
$gist = Invoke-RestMethod $gistUrl -ErrorAction Stop
$gistProfile = $gist.Files."profile.ps1".Content
[version]$gistVersion = "0.0.0"
if ($gistProfile -match $versionRegEx) {
$gistVersion = $matches.Version
Set-Content -Path $latestVersionFile -Value $gistVersion
catch {
# we can hit rate limit issue with GitHub since we're using anonymous
Write-Verbose -Verbose "Was not able to access gist to check for newer version"
if ((Get-Module PSReadLine).Version -lt 2.2) {
throw "Profile requires PSReadLine 2.2+"
# setup psdrives
if ([System.IO.File]::Exists([System.IO.Path]::Combine("$HOME",'test'))) {
New-PSDrive -Root ~/test -Name Test -PSProvider FileSystem -ErrorAction Ignore > $Null
if (!(Test-Path repos:)) {
if (Test-Path ([System.IO.Path]::Combine("$HOME",'git'))) {
New-PSDrive -Root ~/repos -Name git -PSProvider FileSystem > $Null
elseif (Test-Path "d:\PowerShell") {
New-PSDrive -Root D:\ -Name git -PSProvider FileSystem > $Null
Set-PSReadLineOption -Colors @{ Selection = "`e[92;7m"; InLinePrediction = "`e[2m" } -PredictionSource HistoryAndPlugin
Set-PSReadLineKeyHandler -Chord Shift+Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Chord Ctrl+b -Function BackwardWord
Set-PSReadLineKeyHandler -Chord Ctrl+f -Function ForwardWord
Set-PSReadLineKeyHandler -Chord F2 -Function SwitchPredictionView
if ($IsWindows) {
Set-PSReadLineOption -EditMode Emacs -ShowToolTips
Set-PSReadLineKeyHandler -Chord Ctrl+Shift+c -Function Copy
Set-PSReadLineKeyHandler -Chord Ctrl+Shift+v -Function Paste
else {
try {
catch [System.Management.Automation.CommandNotFoundException]
Install-Module Microsoft.PowerShell.UnixTabCompletion -Repository PSGallery -AcceptLicense -Force
# add path to dotnet global tools
$env:PATH += [System.IO.Path]::PathSeparator + [System.IO.Path]::Combine("$HOME",'.dotnet','tools')
# ensure dotnet cli is in path
$dotnet = Get-Command dotnet -CommandType Application -ErrorAction Ignore
if ($null -eq $dotnet) {
if ([System.IO.File]::Exists("$HOME/.dotnet/dotnet")){
$env:PATH += [System.IO.Path]::PathSeparator+ [System.IO.Path]::Combine("$HOME",'.dotnet')
if ($global:profile_initialized -ne $true) {
$global:profile_initialized = $true
$currentLastExitCode = $LASTEXITCODE
$lastSuccess = $?
$color = @{
Reset = "`e[0m"
Red = "`e[31;1m"
Green = "`e[32;1m"
Yellow = "`e[33;1m"
Grey = "`e[37;0m"
White = "`e[37;1m"
Invert = "`e[7m"
RedBackground = "`e[41m"
# set color of PS based on success of last execution
if ($lastSuccess -eq $false) {
$lastExit = $color.Red
} else {
$lastExit = $color.Green
# get the execution time of the last command
$lastCmdTime = ""
$lastCmd = Get-History -Count 1
if ($null -ne $lastCmd) {
$cmdTime = $lastCmd.Duration.TotalMilliseconds
$units = "ms"
$timeColor = $color.Green
if ($cmdTime -gt 250 -and $cmdTime -lt 1000) {
$timeColor = $color.Yellow
} elseif ($cmdTime -ge 1000) {
$timeColor = $color.Red
$units = "s"
$cmdTime = $lastCmd.Duration.TotalSeconds
if ($cmdTime -ge 60) {
$units = "m"
$cmdTIme = $lastCmd.Duration.TotalMinutes
$lastCmdTime = "$($color.Grey)[$timeColor$($cmdTime.ToString("#.##"))$units$($color.Grey)]$($color.Reset) "
# get git branch information if in a git folder or subfolder
$gitBranch = ""
$path = Get-Location
while ($path -ne "") {
if (Test-Path ([System.IO.Path]::Combine($path,'.git'))) {
# need to do this so the stderr doesn't show up in $error
$ErrorActionPreferenceOld = $ErrorActionPreference
$ErrorActionPreference = 'Ignore'
$branch = git rev-parse --abbrev-ref --symbolic-full-name '@{u}'
$ErrorActionPreference = $ErrorActionPreferenceOld
# handle case where branch is local
if ($lastexitcode -ne 0 -or $null -eq $branch) {
$branch = git rev-parse --abbrev-ref HEAD
$branchColor = $color.Green
if ($branch -match "/master") {
$branchColor = $color.Red
$gitBranch = " $($color.Grey)[$branchColor$branch$($color.Grey)]$($color.Reset)"
$path = Split-Path -Path $path -Parent
# truncate the current location if too long
$currentDirectory = $executionContext.SessionState.Path.CurrentLocation.Path
$consoleWidth = [Console]::WindowWidth
$maxPath = [int]($consoleWidth / 2)
if ($currentDirectory.Length -gt $maxPath) {
$currentDirectory = "`u{2026}" + $currentDirectory.SubString($currentDirectory.Length - $maxPath)
# check if running dev built pwsh
$devBuild = ''
if ($PSHOME.Contains("publish")) {
$devBuild = " $($color.White)$($color.RedBackground)DevPwsh$($color.Reset)"
"${lastCmdTime}${currentDirectory}${gitBranch}${devBuild}`n${lastExit}PS$($color.Reset)$('>' * ($nestedPromptLevel + 1)) "
# set window title
try {
$prefix = ''
if ($isWindows) {
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsPrincipal = [Security.Principal.WindowsPrincipal]::new($identity)
if ($windowsPrincipal.IsInRole("Administrators") -eq 1) {
$prefix = "Admin:"
$Host.ui.RawUI.WindowTitle = "$prefix$PWD"
} catch {
# do nothing if can't be set
$global:LASTEXITCODE = $currentLastExitCode
Copy link

danstur commented Apr 8, 2021

@SteveL-MSFT I'm curious why you decided to use gists and the manual handling for this instead of using using git. That's how I sync my profile (although admittedly I update manually to avoid the performance hit of explicitly checking at startup)

I "borrowed" the idea of setting up custom PSDrives for common folders though. I feel stupid for never making that connection - that sounds like it should be very useful.

Copy link

corbob commented Apr 8, 2021

why you decided to use gists and the manual handling for this instead of using using git.

@danstur, not trying to speak for Steve here, but I had the same thought. I'm thinking the reasoning is you don't need to install git to do it this way. That being said, being on a public GitHub project would allow the same thing... Would also allow extra niceties like a license file, and perhaps the version check is pulling down a small file with the version instead of the whole script 🤷‍♂️

Copy link

BigHoss commented Sep 9, 2021

@SteveL-MSFT i try to implement powerline with the following line

Import-Module posh-git
Import-Module oh-my-posh

Set-PoshPrompt -Theme paradox

but i cant seem to find out how or where to correctly implement it with this script

Copy link

@BigHoss , did you ever figure it out?

You would just add those options to the top of the script. The potential issue is that oh-my-posh modifies the function:\prompt so your theme would be overridden with the next declaration of function. You would have to put the code from Steve's prompt' function in the Set-PoshContext` function.

Copy link

codigoperfeito commented Feb 22, 2022

@BigHoss I would recommend you delete the first part of the code and create ur own profile

to delete :

check if newer version
$gistUrl = ""
$latestVersionFile = [System.IO.Path]::Combine("$HOME",'.latest_profile_version')
$versionRegEx = "# Version (?\d+.\d+.\d+)"

to create own profile(open with ur edit code):
exemple with vscode

. code $PROFILE.CurrentUserCurrentHost

and add inside:



. $env:USERPROFILE\.config\user_profile.ps1

and in your "YOUPROFILE.ps1" add the rest of the code, without the part I said not to put with "Module" and "theme", remembering that it is necessary to install the modules first.

my github with code:

My powershell with my theme

Copy link

janegilring commented Aug 5, 2023

Did this work for you without adding -Scope Global?

New-PSDrive -Root ~/repos -Name git -PSProvider FileSystem

In my setup, I had to change the scope in order to see the mapped PSDrives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment