|
| 1 | +<# Base PowerShell Profile |
| 2 | +.SYNOPSIS |
| 3 | + A cross-platform PowerShell profile that sets useful defaults, imports common modules, and provides a custom prompt. |
| 4 | +
|
| 5 | +.DESCRIPTION |
| 6 | + This PowerShell profile works in Windows PowerShell and PowerShell on Windows, Linux, and macOS. It features: |
| 7 | +
|
| 8 | + - Detection of the operating system, PowerShell edition, and host environment. |
| 9 | + - Imports useful modules based on the environment. |
| 10 | + - Sets default options for PSReadLine. |
| 11 | + - Provides a custom prompt that shows admin status, command history, command duration, and current path. |
| 12 | + - Uses Oh My Posh for a rich prompt or a standalone custom prompt when OMP is not installed. |
| 13 | + - Returns a hash table with environment information for use in terminal operations. |
| 14 | +
|
| 15 | +.NOTES |
| 16 | + Author : Sam Erde |
| 17 | + Modified : 2025-09-30 |
| 18 | + GitHub : https://github.com/SamErde/PowerShell |
| 19 | +#> |
| 20 | + |
| 21 | +#region Environment Information |
| 22 | +function Get-EnvironmentInfo { |
| 23 | + # Get environment information for the current session. Returns a hash table. |
| 24 | + [CmdletBinding()] |
| 25 | + |
| 26 | + param () |
| 27 | + |
| 28 | + $IsAdmin = if (($PSVersionTable.PSVersion.Major -le 5) -or $IsWindows) { |
| 29 | + $CurrentUser = [Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent()) |
| 30 | + $CurrentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) |
| 31 | + } else { |
| 32 | + # Must be Linux or macOS, so use the id util. Root has userid of 0. |
| 33 | + 0 -eq (id -u) |
| 34 | + } |
| 35 | + |
| 36 | + if ($PSVersionTable.PSEdition -eq 'Desktop' -or $PSVersionTable.PSVersion -lt '6.0.0') { |
| 37 | + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'PSProfileBase.ps1', Justification = 'This variable was only introduced in PowerShell 6, so no conflict is introduced in Windows PowerShell.')] |
| 38 | + $IsWindows = $true |
| 39 | + if ($Host.Name -eq 'Windows PowerShell ISE Host') { |
| 40 | + $IsPowerShellISE = $true |
| 41 | + } else { |
| 42 | + $IsPowerShellISE = $false |
| 43 | + } |
| 44 | + } else { |
| 45 | + $IsPowerShellISE = $false |
| 46 | + $IsPowerShellCore = $true |
| 47 | + } |
| 48 | + |
| 49 | + return New-Object -TypeName PSCustomObject -Property @{ |
| 50 | + IsAdmin = $IsAdmin |
| 51 | + IsLinux = $IsLinux |
| 52 | + IsMacOS = $IsMacOS |
| 53 | + IsWindows = $IsWindows |
| 54 | + IsPowerShellCore = $IsPowerShellCore |
| 55 | + PSEdition = $PSVersionTable.PSEdition |
| 56 | + IsPowerShellISE = $IsPowerShellISE |
| 57 | + IsVSCode = if ($psEditor) { $true } else { $false } |
| 58 | + IsWindowsTerminal = if ($env:WT_SESSION) { $true } else { $false } |
| 59 | + } |
| 60 | +} # end function Get-EnvironmentInfo |
| 61 | + |
| 62 | +$EnvironmentInfo = Get-EnvironmentInfo |
| 63 | +#endregion Environment Information |
| 64 | + |
| 65 | +#region ImportModules |
| 66 | +# Define modules to import based on OS and PowerShell edition. |
| 67 | +$Modules = @{ |
| 68 | + AllEditions = @('posh-git', 'Terminal-Icons') |
| 69 | + CoreWindows = @('CompletionPredictor', 'Microsoft.WinGet.CommandNotFound') |
| 70 | + CoreNonWindows = @('CompletionPredictor', 'Microsoft.PowerShell.UnixTabCompletion') |
| 71 | +} |
| 72 | + |
| 73 | +# Import all cross-platform modules. |
| 74 | +$Modules.AllEditions | Import-Module |
| 75 | + |
| 76 | +# Import modules for PowerShell on Windows. |
| 77 | +if ($EnvironmentInfo.PSEdition -eq 'Core' -and $IsWindows) { |
| 78 | + $Modules.CoreWindows | Import-Module |
| 79 | +} |
| 80 | + |
| 81 | +if ($EnvironmentInfo.IsVSCode) { |
| 82 | + Import-Module 'EditorServicesCommandSuite' |
| 83 | +} |
| 84 | + |
| 85 | +# Import modules for PowerShell on Linux or macOS. |
| 86 | +if ($IsLinux -or $IsMacOS) { |
| 87 | + $Modules.CoreNonWindows | Import-Module |
| 88 | +} |
| 89 | +#endregion ImportModules |
| 90 | + |
| 91 | +#region Default Settings |
| 92 | +#region Default Settings: PSReadLine |
| 93 | +$PSReadLineOptions = @{ |
| 94 | + HistoryNoDuplicates = $true |
| 95 | + HistorySearchCursorMovesToEnd = $true |
| 96 | +} |
| 97 | +Set-PSReadLineOption @PSReadLineOptions |
| 98 | + |
| 99 | +# Do not write to history file if command was less than 4 characters. Credit: Sean Wheeler. |
| 100 | +$global:__DefaultHistoryHandler = (Get-PSReadLineOption).AddToHistoryHandler |
| 101 | +Set-PSReadLineOption -AddToHistoryHandler { |
| 102 | + param([string]$Line) |
| 103 | + $DefaultResult = $global:__defaultHistoryHandler.Invoke($Line) |
| 104 | + if ($DefaultResult -eq 'MemoryAndFile') { |
| 105 | + if ($Line.Length -gt 3 -and $Line[0] -ne ' ' -and $Line[-1] -ne ';') { |
| 106 | + return 'MemoryAndFile' |
| 107 | + } else { |
| 108 | + return 'MemoryOnly' |
| 109 | + } |
| 110 | + } |
| 111 | + return $DefaultResult |
| 112 | +} # end PSReadLine History Handler |
| 113 | +#endregion Default Settings: PSReadLine |
| 114 | + |
| 115 | +# Set the working location to the Code folder in my home directory. Default to my home directory if the Code folder does not exist. |
| 116 | +if (Test-Path -Path (Join-Path -Path $HOME -ChildPath 'Code') -PathType Container -ErrorAction SilentlyContinue) { |
| 117 | + Set-Location (Join-Path -Path $HOME -ChildPath 'Code') |
| 118 | +} else { |
| 119 | + Set-Location -Path $HOME |
| 120 | +} |
| 121 | +# Set UTF-8 as the default encoding for all input and output operations. |
| 122 | +$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding |
| 123 | +#endregion Default Settings |
| 124 | + |
| 125 | +#region Version Specific Settings |
| 126 | +if ($EnvironmentInfo.PSEdition -eq 'Desktop') { |
| 127 | + # Windows PowerShell Default Settings |
| 128 | + $PSDefaultParameterValues = @{ |
| 129 | + 'ConvertTo-Csv:NoTypeInformation' = $true |
| 130 | + 'ConvertTo-Xml:NoTypeInformation' = $true |
| 131 | + 'Export-Csv:NoTypeInformation' = $true |
| 132 | + 'Format-[WT]*:AutoSize' = $true |
| 133 | + '*:Encoding' = 'utf8' |
| 134 | + 'Out-Default:OutVariable' = 'LastOutput' |
| 135 | + } |
| 136 | + |
| 137 | + Set-PSReadLineOption -PredictionViewStyle ListView -PredictionSource History |
| 138 | + # ProgressPreference can dramatically slow down some scripts in Windows PowerShell. Only enable it when needed. |
| 139 | + Set-Variable -Name ProgressPreference -Value 'SilentlyContinue' |
| 140 | + |
| 141 | +} else { |
| 142 | + # PowerShell [Core] Default Settings |
| 143 | + $PSDefaultParameterValues = @{ |
| 144 | + 'Format-[WT]*:AutoSize' = $true |
| 145 | + 'Out-Default:OutVariable' = 'LastOutput' |
| 146 | + } |
| 147 | + |
| 148 | + Set-PSReadLineOption -PredictionViewStyle ListView -PredictionSource HistoryAndPlugin |
| 149 | + |
| 150 | + <# Detect if connected to a remote session over SSH by checking the value of the $env:SSH_CLIENT environment |
| 151 | + variables. If true, set the default value of the AsOSC52 parameter, which allows you to set the clipboard of |
| 152 | + the local machine when connected to a remote session over SSH. Requires PowerShell 7.4. #> |
| 153 | + $PSDefaultParameterValues['Set-Clipboard:AsOSC52'] = $env:SSH_CLIENT |
| 154 | +} |
| 155 | +#endregion Version Specific Settings |
| 156 | + |
| 157 | +#region Version Specific Prompt |
| 158 | +if ($IsPowerShellISE -or (-not (Get-Command -Name 'oh-my-posh' -ErrorAction SilentlyContinue))) { |
| 159 | + # Known Issue: Due to load order and support issues, this prompt does not render properly in the PowerShell ISE when it is dot sourced from another profile. It does work when placed directly in the ISE profile or run manually. |
| 160 | + # Use a custom prompt without Oh My Posh |
| 161 | + $FolderGlyph = [System.Char]::ConvertFromUtf32([System.Convert]::ToInt32('1F4C1', 16)) |
| 162 | + # Use a red lightning bolt to indicate admin status or a white silhouette for non-admin. |
| 163 | + if ($IsAdmin) { |
| 164 | + $AdminStatus = "$([System.Char]::ConvertFromUtf32([System.Convert]::ToInt32('26A1', 16)))" # Lightning bolt |
| 165 | + $AdminStatusColor = 'Red' |
| 166 | + } else { |
| 167 | + $AdminStatus = "$([System.Char]::ConvertFromUtf32([System.Convert]::ToInt32('1F464', 16)))" # User silhouette |
| 168 | + $AdminStatusColor = 'White' |
| 169 | + } |
| 170 | + # Custom prompt function that shows admin status, command ID, command duration, and path. |
| 171 | + function Prompt { |
| 172 | + $LastCommand = Get-History -Count 1 -ErrorAction SilentlyContinue |
| 173 | + Write-Host "$AdminStatus " -ForegroundColor "$AdminStatusColor" -NoNewline |
| 174 | + Write-Host "[$($LastCommand.Id +1)] $([math]::Ceiling($LastCommand.Duration.TotalMilliseconds))ms " -NoNewline -ForegroundColor White |
| 175 | + Write-Host "$FolderGlyph $($PWD.ToString() -ireplace [regex]::Escape($HOME),'~')" -ForegroundColor Yellow |
| 176 | + Write-Host '>' -NoNewline -ForegroundColor White |
| 177 | + return ' ' |
| 178 | + } |
| 179 | + |
| 180 | +} else { |
| 181 | + # Initialize Oh My Posh prompt when not in PowerShell ISE. To do: Move to a dot file location in home folder and automatically download from GitHub if missing. |
| 182 | + oh-my-posh init pwsh --config "$HOME/.ohmyposh/comply.omp.json" | Invoke-Expression |
| 183 | +} |
| 184 | +#endregion Version Specific Prompt |
0 commit comments