Skip to content

Commit cfe8e8e

Browse files
committed
✨feat: add cross-platform PowerShell profile with environment detection and custom prompt
1 parent f90fa55 commit cfe8e8e

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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

Comments
 (0)