Last active
February 26, 2025 11:16
-
-
Save chrisfcarroll/f3ecb2892f996149ee039d48abb57101 to your computer and use it in GitHub Desktop.
Common Aliases and Paths for PowerShell Profile Microsoft.PowerShell_profile.ps1: editors, paths, git, DevAzure, docker, dotNet, MsBuild, NuGet, IIS, p4merge, poshgit
This file contains 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
# https://gist.github.com/chrisfcarroll/f3ecb2892f996149ee039d48abb57101 | |
# Aliases and Paths for PowerShell Profile ~\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 | |
# | |
# ---------------------------------------------------- | |
# For machines where you have no privileges you should be able to enable scripts for yourself only with: | |
# | |
# `Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` | |
# ---------------------------------------------------- | |
# | |
# Sections: Paths, Editors, Tab Completion, Git abbreviations, Docker abbreviations, other prefs, firstRun and windows installers | |
# | |
Param([switch]$firstRun) | |
# ============================================================================ | |
# -- Paths | |
# Separate secrets from publicly shareable generic profile setup | |
if(test-path ~/.secrets.ps1){ . ~/.secrets.ps1 ; function editsecrets {edit (Resolve-Path ~/.secrets.ps1)} } | |
# Separate current-project specific setup from publically shareable generic profile setup | |
if(test-path ~/abbreviations.ps1){ . ~/abbreviations.ps1 ; function editabbreviations {edit (Resolve-Path ~/abbreviations.ps1)} } | |
# ============================================================================ | |
# My Working Directories | |
# Edit this list to match your usage. | |
# Left hand side is a directory path, right hand side is a commandline alias to use for cd to that path | |
$workDirShortcuts= @{ | |
"~/Repos"="cdr" | |
"~/Deploy"="cdd" | |
"~/Scratch"="cdsu" | |
"~/Scratch-Trusted"="cds" | |
} | |
$notOkay= @{} | |
foreach($sh in $workDirShortcuts.GetEnumerator()){ | |
$myError=$null | |
$globalVarName = (Split-Path $sh.Name -Leaf) -replace "[^a-zA-Z0-9_]","" | |
iex "`$global:$globalVarName = (Resolve-Path $($sh.Name))" -ErrorVariable myError 2>&1 >$null | |
if($myError){ | |
$notOkay.Add( $sh.Name , $sh.Value ) | |
}else{ | |
iex "function $($sh.Value) { Set-Location `$global:$globalVarName}" | |
} | |
} | |
if($notOkay.Count){ | |
Write-Host "Your `$PROFILE script lists these working directory shortcuts which don't exist. Do edit your shortcut list." | |
$notOkay | Out-Host | |
} | |
Remove-Variable workDirShortcuts,notOkay,myError,globalVarName | |
function Add-ToPath( $directoryOrFile, [switch]$applyToWindowsUserPath ){ | |
if(-not $directoryOrFile -gt ""){return} | |
if(-not (Test-Path $directoryOrFile)){return} | |
if((Test-Path $directoryOrFile -PathType Leaf)){$directoryOrFile = Split-Path $directoryOrFile -Parent } | |
$directoryOrFile = (Resolve-Path $directoryOrFile).Path | |
if($env:Path.ToLower().Contains( $directoryOrFile.ToLower()) ) { return } | |
if($applyToWindowsUserPath.IsPresent){ | |
Write-Warning "Adding $directoryOrFile permanently to your User PATH" | |
$userPath=[Environment]::GetEnvironmentVariable("Path","User").Trim(';') | |
[Environment]::SetEnvironmentVariable("Path", "$userPath;$directoryOrFile", 'User') | |
}else{ | |
$env:Path="$($env:PATH.Trim(';'));$directoryOrFile" | |
} | |
} | |
# ============================================================================ | |
# -- Editors | |
# set the edit to command to whichever of sublime, vscode-insiders, vscode, vim we can find, in that order of preference. | |
if(Test-Path "C:\Program Files\Vim\vim90\vim.exe"){$global:EDITOR="C:\Program Files\Vim\vim90\vim.exe"} | |
if(Get-Command code -ea SilentlyContinue) | |
{ | |
New-Alias edit code | |
} | |
elseif (Get-Command code-insiders -ea SilentlyContinue) | |
{ | |
new-alias code code-insiders | |
New-Alias edit code-insiders | |
} | |
elseif(Get-Command subl -ea SilentlyContinue) | |
{ | |
New-Alias edit subl | |
} | |
elseif(Test-Path ~/Applications/sublime_text_build_4126_x64/subl.exe) | |
{ | |
function subl{ ~/Applications/sublime_text_build_4126_x64/subl.exe $args } | |
New-Alias edit subl | |
} | |
function editprofile { edit $PROFILE } | |
if((Test-Path "C:\Program Files\Vim\vim90\vim.exe") -and -not (Get-Command vim -ea SilentlyContinue)) | |
{ | |
New-Alias vim "C:\Program Files\Vim\vim90\vim.exe" | |
New-Alias vi "C:\Program Files\Vim\vim90\vim.exe" | |
} | |
# ============================================================================ | |
# Autocompletion and readline vvv | |
# This now seems to be redundant on newer machines, it's all built-in even for PS5? | |
# Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete | |
# Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward | |
# Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward | |
# Autocompletion ^^^ | |
# ============================================================================ | |
# -- Git | |
Write-Host "Use source command '. pg' to load poshgit" | |
# I used to have poshgit load automatically but it's slow - often 2-3 seconds - | |
# so autoload seems unhelpful if you use new shells a lot | |
function pg { | |
$stopwatchPG=[System.Diagnostics.Stopwatch]::StartNew() | |
Import-Module posh-git -ErrorAction SilentlyContinue | |
Write-Host "PoshGit took $($stopwatchPG.ElapsedMilliseconds)ms" | |
if($?){ | |
$GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true | |
function Get-ShorterPromptPath { | |
(Get-Location).ToString().Replace("$env:USERPROFILE","~") ` | |
-replace '([^\\]{6})([^\\]{4,})\\','$1..\' ` | |
-replace '\\([^\\]{6})([^\\]{3,})([^\\]{6})$','\$1..$3' | |
} | |
$GitPromptSettings.DefaultPromptPath.Text = '$(Get-ShorterPromptPath)' | |
function nll { if(-not $GitPromptSettings.AfterStatus.Text -match "\n"){$GitPromptSettings.AfterStatus.Text += "`n" }} | |
}else{ | |
function prompt { | |
$d=(Get-Location).ToString().Replace("$env:USERPROFILE","~") ` | |
-replace '([^\\]{6})([^\\]{4,})\\','$1..\' ` | |
-replace '\\([^\\]{6})([^\\]{3,})([^\\]{6})$','\$1..$3' | |
"$d> " | |
} | |
} | |
} | |
function gaa { git add $args :/ } | |
function gb { git branch $args } | |
function gbr { git branch --remote $args } | |
function gcliplast { (git show --pretty=oneline | head -n 1) -replace "^[a-f0-9A-F]+ ","" | clip } | |
function gco { git checkout $args} | |
function gitcom { git commit -m "$args"} | |
function gitacom { git commit -a -m "$args"} | |
function gitaaacom { git add :/ ; git commit -m "$args"} | |
function gdiff { git diff $args } | |
function glog { git log ` | |
--pretty=format:'%Cred%h%Creset %C(yellow)%d%Creset %s %Cgreen%cd %C(bold blue)%an%Creset' ` | |
--abbrev-commit --date=format:'%d-%m-%Y %H:%M' $args } | |
function glogg { glog --graph $args } | |
function glog1 {git log --pretty=oneline $args} | |
function grv {get remote --verbose $args} | |
function gs { git status $args } | |
function gpullpush { | |
"Checking ..." | |
git remote update | |
if( ($s=(git status | select-string -Pattern "Your branch is behind|have diverged")).Count ) { | |
$s | |
git pull | |
if( $s -match "can be fast-forwarded.|Successfully rebased and updated"){ | |
"Pushing ..." | |
git push | |
} else { | |
"Merge or rebase wanted. Not pushing." | |
} | |
} else { | |
"Nothing to pull. Pushing ..." | |
git push | |
} | |
Get-Date -DisplayHint DateTime | |
} | |
function openremote { git remote -v | select-string "https://[^ ]+" | Select-Object -First 1 | %{ Start-Process ("$($_.Matches.Value)" -replace "//[^@]+@","//") } } | |
#Git ^^^ | |
# ============================================================================ | |
# -- DevAzure | |
function Open-DevAzure([string][ValidateSet("","build","release","boards","repo","files","pullrequests","branches","tags","commits")]$what) { | |
$remote = "$(git remote -v | select-string "https://[^ ]+" | Select-Object -First 1 -Property {$_.Matches.Value} | Select-Object -ExpandProperty '$_.Matches.Value')" -replace "//[^@]+@","//" | |
if("build","release","boards" -contains $what) | |
{ | |
$remote | select-string "https://[^ ]+(?=/_git)" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)/_$what" } | |
} | |
elseif( "files","repo","" -contains $what) | |
{ | |
$what="" | |
$remote | select-string "https://[^ ]+" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)" } | |
} | |
else | |
{ | |
$remote | select-string "https://[^ ]+" | Select-Object -First 1 | %{ Start-Process "$($_.Matches.Value)/$what" } | |
} | |
} | |
new-alias opendaz Open-DevAzure | |
#DevAzure ^^^ | |
# ============================================================================ | |
# -- Docker | |
if(Get-Command docker -ErrorAction SilentlyContinue){ | |
function dockerdesktop { Start-Process "C:\Program Files\Docker\Docker\Docker Desktop.exe" } | |
function ddls-all { docker container ls -aq } | |
function ddstop-all { docker container stop $(docker container ls -aq) } | |
function ddrm-all { docker container rm $(docker container ls -aq) } | |
} | |
#Docker ^^^ | |
# ============================================================================ | |
# -- AzureCLI | |
if(Get-Command az -ErrorAction SilentlyContinue){ | |
Register-ArgumentCompleter -Native -CommandName az -ScriptBlock { | |
param($commandName, $wordToComplete, $cursorPosition) | |
$completion_file = New-TemporaryFile | |
$env:ARGCOMPLETE_USE_TEMPFILES = 1 | |
$env:_ARGCOMPLETE_STDOUT_FILENAME = $completion_file | |
$env:COMP_LINE = $wordToComplete | |
$env:COMP_POINT = $cursorPosition | |
$env:_ARGCOMPLETE = 1 | |
$env:_ARGCOMPLETE_SUPPRESS_SPACE = 0 | |
$env:_ARGCOMPLETE_IFS = "`n" | |
$env:_ARGCOMPLETE_SHELL = 'powershell' | |
az 2>&1 | Out-Null | |
Get-Content $completion_file | Sort-Object | ForEach-Object { | |
[System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_) | |
} | |
Remove-Item $completion_file, Env:\_ARGCOMPLETE_STDOUT_FILENAME, Env:\ARGCOMPLETE_USE_TEMPFILES, Env:\COMP_LINE, Env:\COMP_POINT, Env:\_ARGCOMPLETE, Env:\_ARGCOMPLETE_SUPPRESS_SPACE, Env:\_ARGCOMPLETE_IFS, Env:\_ARGCOMPLETE_SHELL | |
} | |
} | |
#AzureCLI ^^^ | |
# ============================================================================ | |
# -- Dotnet CLI | |
Add-toPath ~/.dotnet | |
Add-ToPath ~/.dotnet/tools | |
#DotNet ^^^ | |
# ============================================================================ | |
# -- Console Colours for the PowerShell White or Yellow on Blue theme | |
$Host.PrivateData.ErrorForegroundColor = "Yellow" | |
$Host.PrivateData.ErrorBackgroundColor = $Host.UI.RawUI.BackgroundColor | |
$Host.PrivateData.WarningForegroundColor = "DarkYellow" | |
$Host.PrivateData.WarningBackgroundColor = $Host.UI.RawUI.BackgroundColor | |
#Console Colours ^^^ | |
# ============================================================================ | |
# -- Other preferences | |
new-alias gh get-help | |
new-alias ll Get-ChildItem | |
new-alias open start | |
function ss { start-process "https://bing.com/search?q=$([uri]::EscapeDataString($args))" } | |
function pss { start-process "https://bing.com/search?q=$([uri]::EscapeDataString("powershell $args"))" } | |
# which.exe,where.exe,get-command are each subtly different | |
function wh { $r= Get-Command $args ; $r; if($r.GetType() -eq [System.Management.Automation.FunctionInfo]){ $r.ScriptBlock } } | |
if([System.Environment]::OSVersion.Platform -like 'Win*') | |
{ | |
if(Test-Path "$global:onedrive\Commands\AutohotkeyForPCKeyboard.exe"){ | |
new-alias ahwin (Resolve-Path "$global:onedrive\Commands\AutohotkeyForPCKeyboard.exe") | |
} | |
if(Test-Path "$global:onedrive\Commands\AutohotkeyForMacKeyboard.exe"){ | |
new-alias ahmac (Resolve-Path "$global:onedrive\Commands\AutohotkeyForMacKeyboard.exe") | |
} | |
function pgrep([Parameter(Position=0,mandatory=$true)][string]$Name, [switch]$full ) | |
{ | |
Get-WmiObject Win32_Process ` | |
| Where-Object { $_.Name -match $Name -or ( $full -and ($_.CommandLine -match $Name)) } ` | |
| Select-Object -Property ProcessId, Name, CommandLine, Status | |
} | |
} | |
Add-Type -AssemblyName System.IO.Compression.FileSystem | |
function Get-ZippedChildItem { | |
param ( | |
[Parameter(Mandatory=$false)] | |
[string]$Path, | |
[Parameter(Mandatory=$false)] | |
[string]$filePattern | |
) | |
Add-Type -AssemblyName System.IO.Compression.FileSystem | |
if(-not $Path){ | |
'Usage: | |
Get-ZippedChildItem [ -Path ] "archive.zip" [ -FilePattern "file*.* ]" | |
' | |
return | |
} | |
if (-not $Path) {$Path="."} | |
if (-not $ZipPattern) {$ZipPattern="*.zip"} | |
if (-not $filePattern) {$filePattern="*"} | |
Get-ChildItem -Path $Path | ForEach-Object { | |
$zipFile = $_.FullName | |
$zipArchive = [System.IO.Compression.ZipFile]::OpenRead($zipFile) | |
try{ | |
$zipArchive.Entries | Where-Object { $_.Name -like $filePattern } | |
} finally { $zipArchive.Dispose() } | |
} | |
} | |
function Get-ZippedContent{ | |
[OutputType([String])] | |
[CmdletBinding()] | |
Param( $ZipFilePath, $FilePathInZip) | |
$verbose = $VerbosePreference -ne 'SilentlyContinue' | |
if (-not (test-path $ZipFilePath)) { | |
throw "Zip file ""$ZipFilePath"" not found." | |
} | |
try { | |
$Zip = [System.IO.Compression.ZipFile]::OpenRead( (Resolve-Path $ZipFilePath) ) | |
write-verbose "Opened $ZipFilePath : $(($zz.Entries | measure).Count) entries" | |
$matchingEntries= $Zip.Entries | where-object {return $_.FullName -like $FilePathInZip} | |
write-verbose "$(($matchingEntries | measure).Count) entries match ""$FilePathInZip""" | |
$matchingEntries | | |
ForEach-object { | |
write-verbose "Found $($_.FullName)" | |
$ZipStream = $_.Open() | |
try{ | |
$Reader = [System.IO.StreamReader]::new($ZipStream) | |
$s= $Reader.ReadToEnd() | |
write-verbose "Length $($s.Length)" | |
$s | |
} | |
finally{ | |
if($Reader){$Reader.Dispose()} | |
} | |
} | |
} | |
finally {if ($Zip) { $Zip.Dispose() } } | |
} | |
function yesno { | |
while( -not ( ($choice= (Read-Host "May I continue?")) -match "^(ye?s?|no?)$")){ "Y or N ?"} | |
return ($choice -match "^y") | |
} | |
#Other preferences ^^^ | |
# ============================================================================ | |
# -- DotNet Installs | |
class PSChildNameVersionRelease { [string]$PSChildName ; [string]$Version ; [int]$Release; } | |
function Get-InstalledNetFrameworkRuntimes{ | |
[OutputType([PSChildNameVersionRelease])] | |
[CmdletBinding()] | |
Param() | |
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse | | |
Get-ItemProperty -name Version,Release -EA 0 | | |
Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | | |
Sort-Object -Property Version | | |
Select-Object PSChildName, Version, Release | |
} | |
class DisplayNameVersion { [string]$DisplayName ; [string]$DisplayVersion ; } | |
function Get-InstalledDotNetPacks{ | |
[OutputType([DisplayNameVersion])] | |
[CmdletBinding()] | |
Param() | |
Get-ItemProperty ` | |
-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", ` | |
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" | | |
Where-Object {$_.DisplayName -like '*.NET*'} | | |
Select-Object DisplayName, DisplayVersion | | |
Sort-Object -Property DisplayName | |
} | |
#DotNet Installs ^^^ | |
# ============================================================================ | |
# -- IIS | |
function publish-to-iis($fromSolutionDirectory, $toIISAppPath, $publishProfileXmlFileNameNoPath, $buildConfiguration, [switch]$noConfirm) | |
{ | |
if(-not "$fromSolutionDirectory" -or -not "$toIISAppPath" ` | |
-or -not "$publishProfileXmlFileNameNoPath" -or -not "$buildConfiguration"){ | |
Write-Host "Usage: publish-to-iis `$fromSolutionDirectory, `$toIISAppPath, `$publishProfileXmlFileNameNoPath, $buildConfiguration" | |
break | |
} | |
Get-ChildItem $fromSolutionDirectory/$publishProfileXmlFileNameNoPath -recurse | |
Push-Location $fromSolutionDirectory | |
if(Test-Path $toIISAppPath\web.config){ | |
Remove-Item $toIISAppPath\web.config -Verbose | |
}else{ | |
Write-Warning "target web.config doesn't exist. Did you already delete it (or have you set the WRONG target path)?" | |
if(-not $noConfirm){ | |
while( -not ( ($choice= (Read-Host "Press Y to continue or N to stop:")) -match "^(Y|N)$")){ "Y or N ?"} | |
if($choice -ne 'y'){return} | |
} | |
} | |
$publishProfileXmlFileNameNoPath= Split-Path $publishProfileXmlFileNameNoPath -Leaf | |
"Removing directories..." | |
Get-ChildItem $toIISAppPath\* -Directory | | |
ForEach-Object{ $_.Name ; Remove-Item $_ -recurse } | |
Get-ChildItem $toIISAppPath | |
msbuild /p:Configuration=$buildConfiguration /p:DeployOnBuild=true /p:PublishProfile=$publishProfileXmlFileNameNoPath | |
Pop-Location | |
"Finished at $(Get-Date)" | |
} | |
#IIS ^^^ | |
# ============================================================================ | |
# -- First Run and Installers ------------------------------------------------ | |
if($firstRunGit) | |
{ | |
if(Get-Command git -ErrorAction SilentlyContinue - $?){ | |
winget install git.git | |
} | |
git config --global alias.root 'rev-parse --show-toplevel' | |
git config --global alias.lg "log --color --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --graph" | |
git config --global alias.lg1 "log --color --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" | |
if((Get-Command p4merge) -and (Test-Path (Get-Command p4merge).Source)) | |
{ | |
git config --global merge.tool p4merge | |
git config --global diff.tool p4merge | |
} | |
else{Write-Warning "p4merge not found"} | |
Install-Module -Name posh-git -Scope CurrentUser | |
} | |
if($firstRunDotNet){ | |
winget install Microsoft.NuGet | |
winget install Microsoft.DotNet.Framework.DeveloperPack_4 | |
} | |
function Show-MoreWinGetInstallersForDevTools{ | |
@" | |
More WinGet DevTool installers | |
============================== | |
winget install WinMerge.WinMerge | |
winget install Microsoft.VisualStudioCode --override "/mergetasks='!runcode,addcontextmenufiles,addcontextmenufolders,associatewithfiles,addtopath'" --source winget | |
winget install Microsoft.VisualStudio.2022.Enterprise | |
winget install Microsoft.AzureCLI | |
winget install Microsoft.DotNet.Framework.DeveloperPack_4 | |
winget install autohotkey.autohotkey | |
"@ | |
} | |
# ============================================================================ | |
# -- Windows only Visual Studio | |
function Ensure-MsBuild-Git-Nuget-If-WinVS-Installed | |
{ | |
if( [System.Environment]::OSVersion.Platform -notlike "Win*" ){ | |
Write-Error "This function relies on a Visual Studio installation so it only runs on Windows." | |
return | |
} | |
$vswherePath= "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer" | |
if(-not (Test-Path $vswherePath)){ | |
Write-Error "This function relies on a Visual Studio installation but didn't find one in ." | |
Write-Warning "You can install visual studio and the VSWhere tool with winget, e.g.: | |
winget search Microsoft.VisualStudio | |
# winget install <Your Choice of lastest Visual Studio version e.g. Microsoft.VisualStudio.2022.Enterprise/Professional/Community> | |
winget install Microsoft.VisualStudio.2022.Community | |
winget install Microsoft.VisualStudio.Locator | |
" | |
return | |
} | |
Write-Host @" | |
This script will | |
- add Visual Studio MsBuild to your path | |
- add Git to your path | |
- Install NuGet | |
- Install NuGet artifacts credential provider | |
"@ | |
Add-ToPath $vswherePath | |
$findVSComponents = @{ | |
"MSBuild" = @{ Path = "MSBuild\**\Bin\MSBuild.exe" } | |
"Git" = @{ Path = "**\Cmd\Git.exe" } | |
# For more uptodate Git, use winget install git.git instead of using the VS installed version | |
} | |
foreach($required in $findVSComponents.GetEnumerator()){ | |
if(Get-command $required.Key -ErrorAction SilentlyContinue){ | |
Write-Host "$($required.Key) already in path" | |
continue | |
} | |
$componentExe = &vswhere.exe -latest -prerelease -products * -find $required.Value.Path | |
Add-ToPath "$componentExe" -applyToWindowsUserPath | |
if(-not (Get-Command $required.Key -ErrorAction SilentlyContinue)){ | |
Write-Warning "Failed to add $($required.Key) to the path at $componentExe" | |
}else{ | |
"Added $($required.Key) to the path at $componentExe" | |
} | |
} | |
if(-not (Get-Command Git -ErrorAction SilentlyContinue)){ | |
winget install Git.Git | |
Write-Warning "Just installed Git. You could exit and restart powershell for the addition to your path to be picked up." | |
} | |
if(-not (Get-Command NuGet -ErrorAction SilentlyContinue)){ | |
winget install Microsoft.NuGet | |
Write-Warning "Just installed NuGet. You must exit and restart powershell for the addition to your path to be picked up." | |
} | |
Write-Warning "Installing the azure artifacts credential provider for netcore and NetFx." | |
iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) } -AddNetfx" | |
} | |
# Windows only Visual Studio ^^^ | |
Remove-Variable firstRun | |
#First Run ^^^ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment