Last active
April 21, 2025 18:10
-
-
Save david-jarman/bca0fe36ba699885c4156e8aeed8bbac to your computer and use it in GitHub Desktop.
Powershell Core custom profile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace System.Management.Automation | |
using namespace System.Management.Automation.Language | |
if ($host.Name -ne 'ConsoleHost') | |
{ | |
# If not running in the console host, exit. | |
# This speeds up performance for non-interactive sessions. | |
return | |
} | |
Import-Module PSReadLine | |
Import-Module Terminal-Icons | |
Import-Module z | |
$localAppSettingsDir = Resolve-Path "~\AppData\Local" | |
$themeDir = "$localAppSettingsDir\Dev\themes" | |
$themeLocation = "$themeDir\stelbent.minimal.omp.json" | |
$themeGistId = "42a01c8ac0e44739065ce6af09987f01" | |
function Update-PoshTheme { | |
if (-not (Test-Path -Path $themeLocation)) { | |
gh gist clone $themeGistId $themeDir | |
} | |
else { | |
Push-Location $themeDir | |
git pull | |
Pop-Location | |
} | |
} | |
if (-not (Test-Path -Path $themeDir)) { | |
mkdir -Path $themeDir -ErrorAction Continue | |
Update-PoshTheme | |
} | |
oh-my-posh --init --shell pwsh --config $themeLocation | Invoke-Expression | |
$env:GH_EDITOR = 'code --wait' | |
$env:KUBE_EDITOR = 'code --wait' | |
$env:EDITOR = 'code --wait' | |
$env:PYTHONIOENCODING = 'utf8' | |
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock { | |
param($wordToComplete, $commandAst, $cursorPosition) | |
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new() | |
$Local:word = $wordToComplete.Replace('"', '""') | |
$Local:ast = $commandAst.ToString().Replace('"', '""') | |
winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object { | |
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) | |
} | |
} | |
Set-PSReadLineOption -PredictionSource History | |
Set-PSReadLineOption -PredictionViewStyle ListView | |
Set-PSReadLineOption -EditMode Windows | |
Set-PSReadLineOption -AddToHistoryHandler { | |
param($line) | |
# Don't add dotnet user-secrets commands to history | |
if ($line -match '^dotnet\s+user-secrets\s+set.*$') { | |
return $false | |
} | |
# if ($line -match 'llm\s+.*["'']') { | |
# return $false | |
# } | |
return $true | |
} | |
# Powershell Aliases | |
Set-Alias -Name k -Value kubectl.exe | |
Set-Alias -Name unzip -Value Expand-Archive | |
Set-Alias which Get-Command | |
Set-Alias touch New-Item | |
# Git aliases | |
git config --global alias.root 'rev-parse --show-toplevel' # git root now returns the root path of the current git repo | |
git config --global alias.undo 'reset HEAD^' # Undo the last commit | |
# Custom functions | |
function Test-Command { | |
param( | |
[string]$Command | |
) | |
try { | |
Get-Command $Command -ErrorAction Stop | Out-Null | |
} | |
catch { | |
return $false | |
} | |
return $true | |
} | |
function Encrypt-String { | |
$valueToEncrypt = Read-Host -AsSecureString -Prompt "Enter value to encrypt" | |
$key = Read-Host -AsSecureString -Prompt "Enter 16 character key" | |
return ConvertFrom-SecureString -SecureString $valueToEncrypt -SecureKey $key | |
} | |
function Decrypt-String { | |
param( | |
[string]$valueToDecrypt = "" | |
) | |
if ([string]::IsNullOrWhitespace($valueToDecrypt)) { | |
$valueToDecrypt = Read-Host -Prompt "Enter value to decrypt" | |
} | |
$key = Read-Host -AsSecureString -Prompt "Enter 16 character key" | |
$secureString = ConvertTo-SecureString -String $valueToDecrypt -SecureKey $key | |
return ConvertFrom-SecureString -SecureString $secureString -AsPlainText | |
} | |
function ConvertTo-Base64 { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$String | |
) | |
$bytes = [System.Text.Encoding]::UTF8.GetBytes($String) | |
return [System.Convert]::ToBase64String($bytes) | |
} | |
function ConvertFrom-Base64 { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$Base64String | |
) | |
$bytes = [System.Convert]::FromBase64String($Base64String) | |
return [System.Text.Encoding]::UTF8.GetString($bytes) | |
} | |
function Generate-Password { | |
param( | |
[ValidateRange(16, 50)] | |
[int]$length=24 | |
) | |
$symbols = '!@#$%^&*'.ToCharArray(); | |
$characterList = 'a'..'z' + 'A'..'Z' + '0'..'9' + $symbols; | |
do { | |
$password = -join (0..($length-1) | % { $characterList | Get-Random }); | |
[int]$hasLowerChar = $password -cmatch '[a-z]'; | |
[int]$hasUpperChar = $password -cmatch '[A-Z]'; | |
[int]$hasDigit = $password -match '[0-9]'; | |
[int]$hasSymbol = $password.IndexOfAny($symbols) -ne -1; | |
} until (($hasLowerChar + $hasUpperChar + $hasDigit + $hasSymbol) -ge 3) | |
return $password | ConvertTo-SecureString -AsPlainText | |
} | |
function Show-NginxLogs { | |
$nginxControllerPod = kubectl get pods --selector 'app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/component=controller' --template '{{range .items}}{{.metadata.name}}{{end}}' | |
kubectl logs $nginxControllerPod --tail 100 -f | |
} | |
function Sanitize-Path { | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$Path | |
) | |
return $Path.Replace('\', '/') | |
} | |
function Update-Profile { | |
param( | |
[switch]$PushToRemote, | |
[string]$CommitMessage = "Updating profile from $($env:COMPUTERNAME)" | |
) | |
$profileGistId = "bca0fe36ba699885c4156e8aeed8bbac" | |
$profileFileName = "Microsoft.PowerShell_profile.ps1" | |
$localDir = "$PSScriptRoot\.temp-profile" | |
$remoteProfilePath = "$localDir\$profileFileName" | |
Write-Host "Cloning gist to temp folder" | |
gh gist clone $profileGistId $localDir | |
if ($PushToRemote) { | |
Write-Host "Pushing local profile to remote" | |
Get-Content $PROFILE | Out-File $remoteProfilePath | |
pushd $localDir | |
git add $profileFileName | |
git commit -m $CommitMessage | |
git push | |
popd | |
} | |
else { | |
Write-Host "Writing new profile to $PROFILE" | |
Get-Content $remoteProfilePath | Out-File $PROFILE | |
} | |
Remove-Item -Path $localDir -Force -Confirm:$false | |
} | |
$wingetStuff = @( | |
"JanDeDobbeleer.OhMyPosh", | |
"Git.Git", | |
"GitHub.cli", | |
"Microsoft.PowerToys", | |
"Microsoft.AzureCLI", | |
"Microsoft.DotNet.SDK", | |
"Helm.Helm", | |
"Microsoft.Azure.Kubelogin", | |
"Obsidian.Obsidian" | |
) | |
function Install-ProfileDependencies { | |
$wingetStuff | ForEach-Object { | |
Write-Host "Installing $_" | |
winget install $_ | |
} | |
} | |
function Update-ProfileDependencies { | |
$wingetStuff | ForEach-Object { | |
Write-Host "Updating $_" | |
winget upgrade $_ | |
} | |
} | |
# Git functions | |
function Get-DefaultBranch { | |
$defaultBranch = git remote show origin | Select-String -Pattern "HEAD branch" | ForEach-Object { | |
$_ -replace "HEAD branch: ", "" | |
} | |
return $defaultBranch.Trim() | |
} | |
function Rebase-LatestMaster { | |
$currentBranch = git branch --show-current | |
$defaultBranch = Get-DefaultBranch | |
git checkout $defaultBranch | |
git pull | |
git checkout $currentBranch | |
git rebase $defaultBranch | |
} | |
function Get-LatestDefaultBranch { | |
$defaultBranch = Get-DefaultBranch | |
Write-Host "Checking out $defaultBranch" | |
git checkout $defaultBranch; | |
Write-Host "Pulling latest" | |
git pull; | |
} | |
# Powershell functions | |
function Reload-Path { | |
# Get the system and user path | |
$systemPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) | |
$userPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) | |
# Combine the system and user path | |
$combinedPath = $systemPath + ";" + $userPath | |
# Set the path in the shell | |
$env:Path = $combinedPath | |
} | |
function Refresh-TokenInDotEnvFile { | |
param( | |
[string]$Resource, | |
[string]$Key = 'JWT_TOKEN', | |
[string]$EnvFile = '.env' | |
) | |
$tokenJson = az account get-access-token --resource $Resource -o json | ConvertFrom-Json; | |
$token = $tokenJson.accessToken; | |
if (-not (Test-Path -Path $EnvFile)) { | |
New-Item -Path $EnvFile -ItemType File | |
"$Key=$token" | Out-File $EnvFile -Encoding "UTF8" | |
} | |
else { | |
$envFileContent = Get-Content $EnvFile | |
$envFileContent | ForEach-Object { | |
if ($_ -match "^$Key=") { | |
"$Key=$token" | |
} | |
else { | |
$_ | |
} | |
} | Set-Content $EnvFile | |
} | |
} | |
# Other functions | |
# Run a powershell expression as root | |
# Usage: Sudo-Script { <expression> } | |
function Sudo-Script { | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0, Mandatory = $true)] | |
[scriptblock]$ScriptBlock | |
) | |
sudo pwsh -c "$($ScriptBlock.ToString()) && Read-Host 'Press enter to continue...'" | |
} | |
# HTML helpers | |
function Get-WebsiteTitle { | |
param( | |
[string]$url | |
) | |
shot-scraper javascript $url "document.title" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace System.Management.Automation | |
using namespace System.Management.Automation.Language | |
# Performance profiling configuration | |
$script:ProfilePerformanceEnabled = $true | |
$script:ProfilePerformanceTimings = [System.Collections.Generic.List[PSCustomObject]]::new() | |
function Measure-ProfileSection { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true)] | |
[string]$SectionName, | |
[Parameter(Mandatory = $true)] | |
[scriptblock]$ScriptBlock | |
) | |
if ($script:ProfilePerformanceEnabled) { | |
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew() | |
& $ScriptBlock | |
$stopwatch.Stop() | |
$script:ProfilePerformanceTimings.Add([PSCustomObject]@{ | |
Section = $SectionName | |
Time = $stopwatch.ElapsedMilliseconds | |
}) | |
} else { | |
& $ScriptBlock | |
} | |
} | |
function Enable-ProfilePerformance { | |
$script:ProfilePerformanceEnabled = $true | |
$script:ProfilePerformanceTimings.Clear() | |
Write-Host "Profile performance measurement enabled." | |
} | |
function Disable-ProfilePerformance { | |
$script:ProfilePerformanceEnabled = $false | |
Write-Host "Profile performance measurement disabled." | |
} | |
function Show-ProfilePerformance { | |
if ($script:ProfilePerformanceTimings.Count -eq 0) { | |
Write-Host "No performance data available. Run Enable-ProfilePerformance and reload your profile." | |
return | |
} | |
$totalTime = ($script:ProfilePerformanceTimings | Measure-Object -Property Time -Sum).Sum | |
Write-Host "Profile Performance Report" -ForegroundColor Cyan | |
Write-Host "------------------------" -ForegroundColor Cyan | |
$script:ProfilePerformanceTimings | | |
Sort-Object -Property Time -Descending | | |
ForEach-Object { | |
$percentage = [math]::Round(($_.Time / $totalTime) * 100, 1) | |
Write-Host ("{0,-30} {1,6} ms ({2,5}%)" -f $_.Section, $_.Time, $percentage) | |
} | |
Write-Host "------------------------" -ForegroundColor Cyan | |
Write-Host "Total time: $totalTime ms" -ForegroundColor Cyan | |
} | |
# Begin profile execution with performance measurement | |
Measure-ProfileSection "PSReadLine Import" { | |
if ($host.Name -eq 'ConsoleHost') | |
{ | |
Import-Module PSReadLine | |
} | |
} | |
Measure-ProfileSection "Theme Setup" { | |
$localAppSettingsDir = Resolve-Path "~\AppData\Local" | |
$themeDir = "$localAppSettingsDir\Dev\themes" | |
$themeLocation = "$themeDir\stelbent.minimal.omp.json" | |
function Update-PoshTheme { | |
$themeGistId = "42a01c8ac0e44739065ce6af09987f01" | |
if (-not (Test-Path -Path $themeLocation)) { | |
gh gist clone $themeGistId $themeDir | |
} | |
else { | |
Push-Location $themeDir | |
git pull | |
Pop-Location | |
} | |
} | |
if (-not (Test-Path -Path $themeDir)) { | |
mkdir -Path $themeDir -ErrorAction Continue | |
Update-PoshTheme | |
} | |
oh-my-posh --init --shell pwsh --config $themeLocation | Invoke-Expression | |
} | |
Measure-ProfileSection "Import Terminal-Icons module" { | |
Import-Module Terminal-Icons | |
} | |
Measure-ProfileSection "Import z module" { | |
Import-Module z | |
} | |
Measure-ProfileSection "Environment Setup" { | |
$env:GH_EDITOR = "code --wait" | |
$env:KUBE_EDITOR = "code --wait" | |
} | |
Measure-ProfileSection "Register autocompleter for winget" { | |
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock { | |
param($wordToComplete, $commandAst, $cursorPosition) | |
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new() | |
$Local:word = $wordToComplete.Replace('"', '""') | |
$Local:ast = $commandAst.ToString().Replace('"', '""') | |
winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object { | |
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) | |
} | |
} | |
} | |
Measure-ProfileSection "PSReadLine Configuration" { | |
Set-PSReadLineOption -PredictionSource History | |
Set-PSReadLineOption -PredictionViewStyle ListView | |
Set-PSReadLineOption -EditMode Windows | |
Set-PSReadLineOption -AddToHistoryHandler { | |
param($line) | |
# Don't add dotnet user-secrets commands to history | |
if ($line -match '^dotnet\s+user-secrets\s+set.*$') { | |
return $false | |
} | |
# Don't add llm commands to history (turning off for now) | |
# if ($line -match 'llm\s+.*["'']') { | |
# return $false | |
# } | |
return $true | |
} | |
} | |
# Powershell Aliases | |
Measure-ProfileSection "Create Powershell aliases" { | |
Set-Alias -Name k -Value kubectl.exe | |
Set-Alias -Name unzip -Value Expand-Archive | |
Set-Alias which Get-Command | |
Set-Alias touch New-Item | |
} | |
# Git aliases | |
Measure-ProfileSection "Create Git aliases" { | |
git config --global alias.root 'rev-parse --show-toplevel' # git root now returns the root path of the current git repo | |
git config --global alias.undo 'reset HEAD^' # Undo the last commit | |
} | |
# Custom functions | |
function Test-Command { | |
param( | |
[string]$Command | |
) | |
try { | |
Get-Command $Command -ErrorAction Stop | Out-Null | |
} | |
catch { | |
return $false | |
} | |
return $true | |
} | |
function Encrypt-String { | |
$valueToEncrypt = Read-Host -AsSecureString -Prompt "Enter value to encrypt" | |
$key = Read-Host -AsSecureString -Prompt "Enter 16 character key" | |
return ConvertFrom-SecureString -SecureString $valueToEncrypt -SecureKey $key | |
} | |
function Decrypt-String { | |
param( | |
[string]$valueToDecrypt = "" | |
) | |
if ([string]::IsNullOrWhitespace($valueToDecrypt)) { | |
$valueToDecrypt = Read-Host -Prompt "Enter value to decrypt" | |
} | |
$key = Read-Host -AsSecureString -Prompt "Enter 16 character key" | |
$secureString = ConvertTo-SecureString -String $valueToDecrypt -SecureKey $key | |
return ConvertFrom-SecureString -SecureString $secureString -AsPlainText | |
} | |
function ConvertTo-Base64 { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$String | |
) | |
$bytes = [System.Text.Encoding]::UTF8.GetBytes($String) | |
return [System.Convert]::ToBase64String($bytes) | |
} | |
function ConvertFrom-Base64 { | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$Base64String | |
) | |
$bytes = [System.Convert]::FromBase64String($Base64String) | |
return [System.Text.Encoding]::UTF8.GetString($bytes) | |
} | |
function Generate-Password { | |
param( | |
[ValidateRange(16, 50)] | |
[int]$length=24 | |
) | |
$symbols = '!@#$%^&*'.ToCharArray(); | |
$characterList = 'a'..'z' + 'A'..'Z' + '0'..'9' + $symbols; | |
do { | |
$password = -join (0..($length-1) | % { $characterList | Get-Random }); | |
[int]$hasLowerChar = $password -cmatch '[a-z]'; | |
[int]$hasUpperChar = $password -cmatch '[A-Z]'; | |
[int]$hasDigit = $password -match '[0-9]'; | |
[int]$hasSymbol = $password.IndexOfAny($symbols) -ne -1; | |
} until (($hasLowerChar + $hasUpperChar + $hasDigit + $hasSymbol) -ge 3) | |
return $password | ConvertTo-SecureString -AsPlainText | |
} | |
function Show-NginxLogs { | |
$nginxControllerPod = kubectl get pods --selector 'app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/component=controller' --template '{{range .items}}{{.metadata.name}}{{end}}' | |
kubectl logs $nginxControllerPod --tail 100 -f | |
} | |
function Sanitize-Path { | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true)] | |
[string]$Path | |
) | |
return $Path.Replace('\', '/') | |
} | |
function Update-Profile { | |
param( | |
[switch]$PushToRemote, | |
[string]$CommitMessage = "Updating profile from $($env:COMPUTERNAME)" | |
) | |
$profileGistId = "bca0fe36ba699885c4156e8aeed8bbac" | |
$profileFileName = "Microsoft.PowerShell_profile.ps1" | |
$localDir = "$PSScriptRoot\.temp-profile" | |
$remoteProfilePath = "$localDir\$profileFileName" | |
Write-Host "Cloning gist to temp folder" | |
gh gist clone $profileGistId $localDir | |
if ($PushToRemote) { | |
Write-Host "Pushing local profile to remote" | |
Get-Content $PROFILE | Out-File $remoteProfilePath | |
pushd $localDir | |
git add $profileFileName | |
git commit -m $CommitMessage | |
git push | |
popd | |
} | |
else { | |
Write-Host "Writing new profile to $PROFILE" | |
Get-Content $remoteProfilePath | Out-File $PROFILE | |
} | |
Remove-Item -Path $localDir -Force -Confirm:$false | |
} | |
$wingetStuff = @( | |
"JanDeDobbeleer.OhMyPosh", | |
"Git.Git", | |
"GitHub.cli", | |
"Microsoft.PowerToys", | |
"Microsoft.AzureCLI", | |
"Microsoft.DotNet.SDK", | |
"Helm.Helm", | |
"Microsoft.Azure.Kubelogin", | |
"Obsidian.Obsidian" | |
) | |
function Install-ProfileDependencies { | |
$wingetStuff | ForEach-Object { | |
Write-Host "Installing $_" | |
winget install $_ | |
} | |
} | |
function Update-ProfileDependencies { | |
$wingetStuff | ForEach-Object { | |
Write-Host "Updating $_" | |
winget upgrade $_ | |
} | |
} | |
# Git functions | |
function Get-DefaultBranch { | |
$defaultBranch = git remote show origin | Select-String -Pattern "HEAD branch" | ForEach-Object { | |
$_ -replace "HEAD branch: ", "" | |
} | |
return $defaultBranch.Trim() | |
} | |
function Rebase-LatestMaster { | |
$currentBranch = git branch --show-current | |
$defaultBranch = Get-DefaultBranch | |
git checkout $defaultBranch | |
git pull | |
git checkout $currentBranch | |
git rebase $defaultBranch | |
} | |
function Get-LatestDefaultBranch { | |
$defaultBranch = Get-DefaultBranch | |
Write-Host "Checking out $defaultBranch" | |
git checkout $defaultBranch; | |
Write-Host "Pulling latest" | |
git pull; | |
} | |
# Powershell functions | |
function Reload-Path { | |
# Get the system and user path | |
$systemPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) | |
$userPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) | |
# Combine the system and user path | |
$combinedPath = $systemPath + ";" + $userPath | |
# Set the path in the shell | |
$env:Path = $combinedPath | |
} | |
function Refresh-TokenInDotEnvFile { | |
param( | |
[string]$Resource, | |
[string]$Key = 'JWT_TOKEN', | |
[string]$EnvFile = '.env' | |
) | |
$tokenJson = az account get-access-token --resource $Resource -o json | ConvertFrom-Json; | |
$token = $tokenJson.accessToken; | |
if (-not (Test-Path -Path $EnvFile)) { | |
New-Item -Path $EnvFile -ItemType File | |
"$Key=$token" | Out-File $EnvFile -Encoding "UTF8" | |
} | |
else { | |
$envFileContent = Get-Content $EnvFile | |
$envFileContent | ForEach-Object { | |
if ($_ -match "^$Key=") { | |
"$Key=$token" | |
} | |
else { | |
$_ | |
} | |
} | Set-Content $EnvFile | |
} | |
} | |
# Other functions | |
# Run a powershell expression as root | |
# Usage: Sudo-Script { <expression> } | |
function Sudo-Script { | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0, Mandatory = $true)] | |
[scriptblock]$ScriptBlock | |
) | |
sudo pwsh -c "$($ScriptBlock.ToString()) && Read-Host 'Press enter to continue...'" | |
} | |
# Function to generate a regex for an acronym | |
function Get-AcronymRegex { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0, HelpMessage = "Enter the acronym to generate the regex for")] | |
[string]$Acronym | |
) | |
# Escape each letter of the acronym and create a regex pattern | |
$pattern = ($Acronym.ToCharArray() | ForEach-Object { "(?i:\b$_\w*\b)" }) -join '\s+' | |
return $pattern | |
} | |
if ($script:ProfilePerformanceEnabled) { | |
Show-ProfilePerformance | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment