Sharing my PowerShell Profile

Windows PowerShell

Over the course of the last several months, I’ve collected several snippets for my PowerShell profile. Your PowerShell profile is loaded each time you start PowerShell. The official documentation for it can be found here: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-6

To get started, you can easily edit your profile by typing notepad $profile to load your profile. The PowerShell prompt and PowerShell ISE each have their own profile but I like mine to be the same so here’s what I did:

  1. First, I created a profile.ps1 file in $home\Documents\WindowsPowerShell\. This is also where you’ll find the default profile files, Microsoft.PowerShell_profile.ps1 and Microsoft.PowerShellISE_profile.ps1.
  2. Second, in the default files, just add a line to redirect the profile like so:
    $profile="$home\Documents\WindowsPowerShell\profile.ps1"
  3. Third, save all 3 files. Next time you open PowerShell or the ISE, it will load your profile.ps1 (which might be empty at this point).

Let’s walk through what’s in my profile.ps1. At the end, I’ll include a link so you can download it in its entirety.

Logging and PSReadLine

Here I’m setting my log path and will log everything I type so I have a full transcript of my session if ever I need it. Next, some PSReadLine settings. @roggenk has a good blog post that covers PSReadLine in some detail so head over and check that out. I’ve got some of the same settings here that improve the user experience. I have two custom key bindings, one to start the @vivaldibrowser browser (my favorite browser!) and switches focus to the browser right away and the other to perform a git commit/push.

#Logging
#Logging
$PSLogPath = ("{0}{1}\Documents\WindowsPowerShell\log\{2:yyyyMMdd}-{3}.log" -f $env:HOMEDRIVE, $env:HOMEPATH,  (Get-Date), $PID)
Add-Content -Value "# $(Get-Date) $env:username $env:computername" -Path $PSLogPath -erroraction SilentlyContinue
Add-Content -Value "# $(Get-Location)" -Path $PSLogPath -erroraction SilentlyContinue

# PSReadLine Settings
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward 
Set-PSReadlineOption -BellStyle None #Disable ding on typing error
Set-PSReadlineOption -EditMode Emacs #Make TAB key show parameter options
Set-PSReadlineKeyHandler -Key Ctrl+i -ScriptBlock { Start-Process "${env:ProgramFiles(x86)}\vivaldi\Application\vivaldi.exe" -ArgumentList "https://www.bing.com" } #KEY: Load Browsers using key "C:\Program Files (x86)\Vivaldi\Application\vivaldi.exe"

#KEY: Git, press Ctrl+Shift+G (case sensitive)
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
} 

Functions

Next step, some functions. The first one just shows some nice output to get the current directory size, which should be built-in! The next one checks to see if the PowerShell prompt is running as an administrator; you’ll see why we need this later. I stole borrowed both of these from @jaredtrog including most of the other stuff in my prompt below (next section).

#Functions
function Get-DirectorySize($Path='.',$InType="MB")
{
    $colItems = (Get-ChildItem $Path -recurse | Measure-Object -property length -sum)
    switch ($InType) {
        "GB" { $ret = "{0:N2}" -f ($colItems.sum / 1GB) + " GB" }
        "MB" { $ret = "{0:N2}" -f ($colItems.sum / 1MB) + " MB" }
        "KB" { $ret = "{0:N2}" -f ($colItems.sum / 1KB) + " KB"}
        "B" { $ret = "{0:N2}" -f ($colItems.sum) + " B"}
        Default { $ret = "{0:N2}" -f ($colItems.sum) + " B" }
    }
    Return $ret
}
function Test-IsAdmin {
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
}

The Prompt

Finally, here’s my prompt. You’ll see the Test-IsAdmin function being used here to set the prompt’s text color. This is really useful to know immediately if you’re running an elevated prompt.

function global:prompt {
    #Put the full path in the title bar

    $console = $host.ui.RawUI
    $console.ForegroundColor = "gray"
    $host.UI.RawUI.WindowTitle = Get-Location

    #Set text color based on admin
    if (Test-IsAdmin) {
        $userColor = 'Red'
    }
    else {
        $userColor = 'White'
    }

    #Setup command line numbers
    $LastCmd = Get-History -Count 1
    if($LastCmd)
    {
        $lastId = $LastCmd.Id
        
        Add-Content -Value "# $($LastCmd.StartExecutionTime)" -Path $PSLogPath
        Add-Content -Value "$($LastCmd.CommandLine)" -Path $PSLogPath
        Add-Content -Value "" -Path $PSLogPath
    }

    $nextCommand = $lastId + 1
    $fullPath = Get-Location

    Write-Host "[$($pwd)]" -ForegroundColor "Cyan"
    Write-Host -NoNewline '[' -ForegroundColor "Gray"
    Write-Host -NoNewline "$([System.Environment]::UserName)" -ForegroundColor $userColor
    Write-Host -NoNewline '@'
    Write-Host -NoNewline "$([System.Environment]::MachineName)  $nextCommand" -ForegroundColor $userColor
    Write-Host -NoNewline ']' -ForegroundColor "Gray"
    #Use $host.EnterNestedPrompt() to test a nested prompt. 
    Write-Host -NoNewline " PS$('>' * ($nestedPromptLevel + 1)) " -ForegroundColor $userColor
    Return " "
} 

Here’s how it looks:

PowerShell Prompt

Having the folder path on its own line gives me more space to focus on my account PowerShell command. Here’s how the Administrator prompt looks:

PowerShell Prompt as Administrator

Notice the red text. Almost forgot the nice ASCII. Just use any online ASCII generator and use Write-Host.

Clear-Host
Write-Host '   _       __      __    _     __'
Write-Host '  | |     / /___ _/ /_  (_)___/ /'
Write-Host '  | | /| / / __ `/ __ \/ / __  / '
Write-Host '  | |/ |/ / /_/ / / / / / /_/ /  '
Write-Host '  |__/|__/\__,_/_/ /_/_/\__,_/   '
Write-Host '                                 ' 

That’s all! If you have any other tips, share them in the comments below.

0 comments… add one

Leave a Reply