Skip to content

Instantly share code, notes, and snippets.

@akunzai
Last active June 11, 2026 04:48
Show Gist options
  • Select an option

  • Save akunzai/3af259df54dcdd6073293e6f8efe8dbf to your computer and use it in GitHub Desktop.

Select an option

Save akunzai/3af259df54dcdd6073293e6f8efe8dbf to your computer and use it in GitHub Desktop.
My PowerShell profile
# https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_profiles
# Windows for PowerShell < 6: $Home\[My]Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
# Windows for PowerShell >= 6: $Home\[My]Documents\PowerShell\Microsoft.PowerShell_profile.ps1
# Linux/macOS: ~/.config/powershell/Microsoft.PowerShell_profile.ps1
# https://github.com/microsoft/msbuild/issues/1596
$env:DOTNET_CLI_UI_LANGUAGE = 'en-us'
$env:RUNNER_SHELL = 'powershell'
# https://github.com/PowerShell/PSReadLine
if (Get-Command 'Set-PSReadlineKeyHandler' -ErrorAction SilentlyContinue)
{
# Bind the Ctrl+D key to exit the PowerShell
Set-PSReadlineKeyHandler -Chord ctrl+d -Function ViExit -ErrorAction SilentlyContinue
# Bind the Ctrl+W key to delete word before cursor
Set-PSReadlineKeyHandler -Chord ctrl+w -Function BackwardDeleteWord
# Bind the Ctrl+E key to move cursor to the end of line
Set-PSReadlineKeyHandler -Chord ctrl+e -Function EndOfLine
# Bind the Ctrl+A key to move cursor to the begin of line
Set-PSReadlineKeyHandler -Chord ctrl+a -Function BeginningOfLine
}
if (Get-Command 'Set-PSReadLineOption' -ErrorAction SilentlyContinue)
{
# Enable Predictive IntelliSense
try
{
Set-PSReadLineOption -PredictionSource History -ErrorAction Stop
} catch
{
}
# https://github.com/dracula/powershell
Set-PSReadlineOption -Color @{
"Command" = [ConsoleColor]::Green
"Parameter" = [ConsoleColor]::Gray
"Operator" = [ConsoleColor]::Magenta
"Variable" = [ConsoleColor]::White
"String" = [ConsoleColor]::Yellow
"Number" = [ConsoleColor]::Blue
"Type" = [ConsoleColor]::Cyan
"Comment" = [ConsoleColor]::DarkCyan
}
}
if ($PSVersionTable.PSVersion.Major -lt 6)
{
# Passing output between PowerShell cmdlets
# https://stackoverflow.com/questions/40098771/changing-powershells-default-output-encoding-to-utf-8
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
# Passing output from PowerShell to Native Application
# https://gist.github.com/xoner/4671514
$OutputEncoding = [console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
# Enable TLS 1.2 and TLS 1.3
try
{
[Net.ServicePointManager]::SecurityProtocol = 'Tls12, Tls13'
} catch
{
[Net.ServicePointManager]::SecurityProtocol = 'Tls12'
}
# Progress bar can significantly impact cmdlet performance
# https://github.com/PowerShell/PowerShell/issues/2138
$ProgressPreference = 'SilentlyContinue'
}
# https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_prompts
function prompt
{
$suffix = '$'
$isWin = $IsWindows -or ($env:OS -like "*Windows*") -or ([Environment]::OSVersion.Platform -eq [PlatformID]::Win32NT)
if ($isWin)
{
# Using string-based type retrieval prevents parsing errors on Linux/macOS during profile load
$identityType = [Type]::GetType("System.Security.Principal.WindowsIdentity")
if ($identityType)
{
$identity = $identityType::GetCurrent()
$principalType = [Type]::GetType("System.Security.Principal.WindowsPrincipal")
$principal = New-Object $principalType -ArgumentList $identity
$roleType = [Type]::GetType("System.Security.Principal.WindowsBuiltInRole")
if ($principal.IsInRole($roleType::Administrator))
{
$suffix = '#'
}
}
}
if (Test-Path variable:/PSDebugContext)
{
Write-Host 'DBG: ' -ForegroundColor Blue -NoNewline
}
Write-Host "$($executionContext.SessionState.Path.CurrentLocation) " -ForegroundColor Yellow -NoNewline
Write-Host "| $(Get-Date -Format 'HH:mm')" -ForegroundColor Green
return "$suffix "
}
if ($IsWindows -or [Environment]::OSVersion.Platform -eq [PlatformID]::Win32NT)
{
$gitLess = "$env:ProgramFiles\Git\usr\bin\less.exe"
if (!(Get-Command 'less' -ErrorAction SilentlyContinue) -and (Test-Path($gitLess)))
{
Set-Alias less $gitLess
}
# Remove default PowerShell curl alias to let native curl.exe take over naturally
if (Get-Alias curl -ErrorAction SilentlyContinue)
{
Remove-Item alias:curl -Force -ErrorAction SilentlyContinue
}
function up
{
Update-Module -ErrorAction SilentlyContinue
# https://scoop.sh/
if (Get-Command 'scoop' -ErrorAction SilentlyContinue)
{
scoop update
scoop update '*'
scoop cleanup '*' --cache
}
# https://github.com/microsoft/winget-cli
if (Get-Command 'winget' -ErrorAction SilentlyContinue)
{
winget upgrade --all --silent
}
}
function touch
{
Param(
[Parameter(Mandatory = $true)]
[string]$Path
)
if (Test-Path -LiteralPath $Path -ErrorAction SilentlyContinue)
{
(Get-Item -LiteralPath $Path).LastWriteTime = Get-Date
} else
{
New-Item -Type File -LiteralPath $Path
}
}
function grep
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
$InputObject,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$GrepArgs
)
begin
{
$gitGrep = "$env:ProgramFiles\Git\usr\bin\grep.exe"
# Choose the search command
if (Get-Command 'rg' -ErrorAction SilentlyContinue)
{
$scriptBlock = { rg $GrepArgs }
} elseif (Test-Path $gitGrep -ErrorAction SilentlyContinue)
{
$scriptBlock = { &$gitGrep $GrepArgs }
} else
{
$scriptBlock = { findstr /sipn $GrepArgs }
}
$pipelineData = [System.Collections.Generic.List[string]]::new()
}
process
{
if ($PSBoundParameters.ContainsKey('InputObject') -and $null -ne $InputObject)
{
$pipelineData.Add($InputObject)
}
}
end
{
if ($pipelineData.Count -gt 0)
{
$pipelineData | &$scriptBlock
} elseif (-not $PSBoundParameters.ContainsKey('InputObject'))
{
&$scriptBlock
}
}
}
# https://github.com/Microsoft/vswhere/wiki/Start-Developer-Command-Prompt
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere -ErrorAction SilentlyContinue)
{
# https://intellitect.com/enter-vsdevshell-powershell/
# https://devblogs.microsoft.com/visualstudio/say-hello-to-the-new-visual-studio-terminal/
function Start-VsDevShell
{
$vsInstallPath = & $vsWhere -latest -property installationPath
$vsDevShellModule = Join-Path $vsInstallPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
Import-Module $vsDevShellModule -ErrorAction SilentlyContinue
Enter-VsDevShell -VsInstallPath "$vsInstallPath" -SkipAutomaticLocation
}
Set-Alias vsdevshell Start-VsDevShell
}
}
$profileRoot = if ($PSScriptRoot)
{ $PSScriptRoot
} else
{ Split-Path -Parent $PROFILE
}
$profileHomes = @(
$profileRoot,
(Join-Path $profileRoot $([Environment]::OSVersion.Platform)))
if ($env:USERPROFILE)
{
$profileHomes += $env:USERPROFILE
$profileHomes += (Join-Path $env:USERPROFILE $([Environment]::OSVersion.Platform))
}
foreach ($profileHome in $profileHomes)
{
$profilePath = Join-Path $profileHome "profile.ps1"
if (Test-Path $profilePath -ErrorAction SilentlyContinue)
{
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
. $profilePath
Write-Host "Loading $profilePath took $($stopWatch.ElapsedMilliseconds)ms."
}
}
# Custom PowerShell Profile
# Put your custom aliases, functions, and environment variables here.
# This file is automatically loaded by Microsoft.PowerShell_profile.ps1
function Get-Path
{
<#
.SYNOPSIS
Displays the PATH environment variable, showing each directory on a new line, numbered, and indicating if it exists.
.EXAMPLE
Get-Path
#>
$paths = $env:PATH -split ';' | Where-Object { $_ }
for ($i = 0; $i -lt $paths.Count; $i++)
{
$path = $paths[$i]
$exists = Test-Path -LiteralPath $path -ErrorAction SilentlyContinue
$color = if ($exists)
{ "Green"
} else
{ "Red"
}
$status = if ($exists)
{ "OK"
} else
{ "Not Found"
}
Write-Host ("[{0:D2}] " -f ($i + 1)) -NoNewline -ForegroundColor Gray
Write-Host "$path " -NoNewline
Write-Host $status -ForegroundColor $color
}
}
function Add-Path
{
<#
.SYNOPSIS
Adds a directory to the persistent User or System PATH environment variable.
.PARAMETER Path
The directory path to add.
.PARAMETER Scope
The scope to add the path to. Either 'User' (default) or 'Machine'/'System'.
.EXAMPLE
Add-Path -Path "C:\Tools" -Scope User
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Path,
[Parameter(Position = 1)]
[ValidateSet('User', 'Machine', 'System')]
[string]$Scope = 'User'
)
# Get absolute path
$resolvedPath = (Resolve-Path -LiteralPath $Path -ErrorAction SilentlyContinue).ProviderPath
if (!$resolvedPath)
{
$resolvedPath = (Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue).FullName
}
if (!$resolvedPath)
{
Write-Error "The directory path '$Path' does not exist."
return
}
$targetScope = if ($Scope -eq 'User')
{ [EnvironmentVariableTarget]::User
} else
{ [EnvironmentVariableTarget]::Machine
}
# Retrieve current persistent PATH
$currentPath = [Environment]::GetEnvironmentVariable('Path', $targetScope)
$pathParts = $currentPath -split ';' | Where-Object { $_ }
if ($pathParts -contains $resolvedPath)
{
Write-Host "Path '$resolvedPath' is already in the persistent $Scope PATH." -ForegroundColor Yellow
return
}
# Append path and update persistently
$newPath = ($pathParts + $resolvedPath) -join ';'
try
{
[Environment]::SetEnvironmentVariable('Path', $newPath, $targetScope)
# Update current session as well
$env:PATH = ($env:PATH -split ';' | Where-Object { $_ -ne $resolvedPath } ) + $resolvedPath -join ';'
Write-Host "Successfully added '$resolvedPath' to persistent $Scope PATH." -ForegroundColor Green
} catch
{
Write-Error "Failed to update $Scope PATH. You might need to run PowerShell as Administrator for Machine/System scope."
}
}
function Remove-Path
{
<#
.SYNOPSIS
Removes a directory from the persistent User or System PATH environment variable.
.PARAMETER Path
The directory path to remove, or its index number from Get-Path.
.PARAMETER Scope
The scope to remove the path from. Either 'User' (default) or 'Machine'/'System'.
.EXAMPLE
Remove-Path -Path "C:\Tools" -Scope User
.EXAMPLE
Remove-Path 5
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Path,
[Parameter(Position = 1)]
[ValidateSet('User', 'Machine', 'System')]
[string]$Scope = 'User'
)
# Check if the input is a number (index)
if ($Path -match '^\d+$')
{
$index = [int]$Path - 1
$currentPaths = $env:PATH -split ';' | Where-Object { $_ }
if ($index -ge 0 -and $index -lt $currentPaths.Count)
{
$pathToRemove = $currentPaths[$index]
Write-Host "Index $Path resolved to '$pathToRemove'." -ForegroundColor Gray
} else
{
Write-Error "Index $Path is out of range. Run Get-Path to see valid indices."
return
}
} else
{
# Try to resolve path, but fall back to literal string if it cannot be resolved
$resolvedPath = (Resolve-Path -LiteralPath $Path -ErrorAction SilentlyContinue).ProviderPath
if (!$resolvedPath)
{
$resolvedPath = (Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue).FullName
}
$pathToRemove = if ($resolvedPath)
{ $resolvedPath
} else
{ $Path
}
}
$targetScope = if ($Scope -eq 'User')
{ [EnvironmentVariableTarget]::User
} else
{ [EnvironmentVariableTarget]::Machine
}
# Retrieve current persistent PATH
$currentPath = [Environment]::GetEnvironmentVariable('Path', $targetScope)
$pathParts = $currentPath -split ';' | Where-Object { $_ }
# Check if path exists in the list (case-insensitive comparison)
$matchingParts = $pathParts | Where-Object { $_ -eq $pathToRemove -or $_ -eq $Path }
if (!$matchingParts)
{
Write-Host "Path '$pathToRemove' was not found in the persistent $Scope PATH." -ForegroundColor Yellow
return
}
# Remove the path parts
$newPathParts = $pathParts | Where-Object { $_ -ne $pathToRemove -and $_ -ne $Path }
$newPath = $newPathParts -join ';'
try
{
[Environment]::SetEnvironmentVariable('Path', $newPath, $targetScope)
# Update current session as well
$env:PATH = ($env:PATH -split ';' | Where-Object { $_ -and $_ -ne $pathToRemove -and $_ -ne $Path }) -join ';'
Write-Host "Successfully removed '$pathToRemove' from persistent $Scope PATH." -ForegroundColor Green
} catch
{
Write-Error "Failed to update $Scope PATH. You might need to run PowerShell as Administrator for Machine/System scope."
}
}
function New-Link
{
<#
.SYNOPSIS
Creates a symbolic link, hard link, or directory junction, mimicking Linux 'ln'.
.PARAMETER Target
The target path to link to.
.PARAMETER Link
The path of the link to create. If omitted, defaults to the leaf name of Target in the current directory.
.PARAMETER Symbolic
Create a symbolic link (default is hard link). For directories, automatically uses a Junction to avoid requiring administrator privileges.
.PARAMETER Force
Force creation of the link by removing any existing file or directory at the link path first.
.EXAMPLE
ln target.txt link.txt
.EXAMPLE
ln -s target_dir link_dir
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Target,
[Parameter(Position = 1)]
[string]$Link,
[Alias('s')]
[switch]$Symbolic,
[Alias('f')]
[switch]$Force
)
# Resolve Target relative to current directory if it exists
if (-not (Test-Path -LiteralPath $Target))
{
Write-Error "The target '$Target' does not exist. The target must exist to determine the link type (File or Directory)."
return
}
$item = Get-Item -LiteralPath $Target
$resolvedTarget = $item.FullName
$isDir = $item -is [System.IO.DirectoryInfo]
# If Link is not specified, default to the leaf name of Target in the current directory
if ([string]::IsNullOrEmpty($Link))
{
$Link = Split-Path -Path $Target -Leaf
}
# If Force is specified and Link already exists, remove it first
if (Test-Path -LiteralPath $Link)
{
if ($Force)
{
$linkItem = Get-Item -LiteralPath $Link -Force
if ($linkItem.Attributes -match 'ReparsePoint' -or $linkItem -is [System.IO.DirectoryInfo])
{
Remove-Item -LiteralPath $Link -Force -Recurse:$false -ErrorAction Stop
} else
{
Remove-Item -LiteralPath $Link -Force -ErrorAction Stop
}
} else
{
Write-Error "The link path '$Link' already exists. Use -f or -Force to overwrite."
return
}
}
# Determine link type
if ($Symbolic)
{
if ($isDir)
{
# Use Junction for directories to avoid elevation requirement
$itemType = 'Junction'
} else
{
$itemType = 'SymbolicLink'
}
} else
{
if ($isDir)
{
Write-Error "Cannot hard link a directory. Use -s or -Symbolic to create a directory link."
return
}
$itemType = 'HardLink'
}
try
{
New-Item -ItemType $itemType -Path $Link -Value $resolvedTarget -ErrorAction Stop | Out-Null
Write-Host "Created $($itemType): $Link -> $resolvedTarget" -ForegroundColor Green
} catch
{
$err = $_.Exception.Message
if ($err -match "NewItemSymbolicLinkElevationRequired" -or $_.Exception.GetType().FullName -eq "System.UnauthorizedAccessException")
{
Write-Error "Administrator privilege or Developer Mode is required to create a symbolic link for files. Try running PowerShell as Administrator, or enable Windows Developer Mode."
} else
{
Write-Error "Failed to create link: $err"
}
}
}
Set-Alias -Name ln -Value New-Link -Force
if (Get-Command 'git' -ErrorAction SilentlyContinue)
{
function rgit()
{
$params = $args
$currentPath = $pwd.Path
# Prevent accidental run in root or C:\ or user profile without confirmation to avoid long freezing scans
if ($currentPath -eq $env:USERPROFILE -or $currentPath -match '^[a-zA-Z]:\\$')
{
$choice = Read-Host "You are in a root or home directory ($currentPath). Are you sure you want to search recursively? (y/N)"
if ($choice -notmatch '^[yY]')
{
Write-Warning "Operation cancelled."
return
}
}
# Fast BFS traversal that skips common build/dependency folders and avoids scanning inside Git repos
$queue = [System.Collections.Generic.Queue[string]]::new()
$queue.Enqueue($currentPath)
while ($queue.Count -gt 0)
{
$dir = $queue.Dequeue()
$gitDir = Join-Path $dir ".git"
if (Test-Path $gitDir -ErrorAction SilentlyContinue)
{
Write-Output "$($dir): git $params"
git -C $dir $params
continue # Skip scanning deeper inside this Git repository
}
Get-ChildItem -LiteralPath $dir -Directory -Force -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Name -notmatch '^(node_modules|\.git|bin|obj|vendor|\.venv|\.gradle|\.cargo|target)$')
{
$queue.Enqueue($_.FullName)
}
}
}
}
}
# https://github.com/fork-dev/TrackerWin/issues/416
$fork = "${env:LocalAppData}\Fork\current\Fork.exe"
if (Test-Path $fork)
{
function fork
{
$path = if ($args.Count -gt 0)
{ $args[0]
} else
{ '.'
}
# Fork requires an absolute path; get ProviderPath to avoid filesystem prefix issues
$resolvedPath = (Resolve-Path -LiteralPath $path -ErrorAction SilentlyContinue).ProviderPath
if (-not $resolvedPath)
{
$resolvedPath = (Get-Item -LiteralPath $path -ErrorAction SilentlyContinue).FullName
}
if ($resolvedPath)
{
&$fork $resolvedPath
} else
{
Write-Error "Path '$path' could not be resolved."
}
}
}
if (Get-Command 'agy' -ErrorAction SilentlyContinue)
{
function agy.yolo
{
<#
.SYNOPSIS
Starts Antigravity CLI (agy) in YOLO mode (auto-approving all permissions).
.EXAMPLE
agy.yolo
#>
agy --dangerously-skip-permissions $args
}
}
if (Get-Command 'claude' -ErrorAction SilentlyContinue)
{
function cc.yolo
{
<#
.SYNOPSIS
Starts Claude Code CLI in YOLO mode (auto-approving all permissions).
.EXAMPLE
cc.yolo
#>
claude --dangerously-skip-permissions $args
}
}
if (Get-Command 'codex' -ErrorAction SilentlyContinue)
{
function cd.yolo
{
<#
.SYNOPSIS
Starts Codex CLI in YOLO mode (auto-approving all permissions).
.EXAMPLE
cd.yolo
#>
codex --yolo $args
}
}
# https://starship.rs/
if (Get-Command 'starship' -ErrorAction SilentlyContinue)
{
Invoke-Expression (&starship init powershell)
}
@akunzai

akunzai commented May 31, 2026

Copy link
Copy Markdown
Author
# Define target paths
$psDir = Join-Path $env:UserProfile "Documents\PowerShell"
$psLink = Join-Path $env:UserProfile "Documents\WindowsPowerShell"
$profilePath = Join-Path $psDir "Microsoft.PowerShell_profile.ps1"
$gistUrl = "https://gist.githubusercontent.com/akunzai/3af259df54dcdd6073293e6f8efe8dbf/raw/9c0f5ba48e4a4913c640204b3fcdb8383c798a1c/Microsoft.PowerShell_profile.ps1"

# 1. Ensure the directory exists
if (-not (Test-Path $psDir)) {
    New-Item -ItemType Directory -Path $psDir -Force | Out-Null
    Write-Host "Created directory: $psDir" -ForegroundColor Green
}

# 2. Create Symbolic Link
# Remove existing link/file if present to avoid collision
if (Test-Path $psLink) {
    if ((Get-Item $psLink).LinkType -eq 'SymbolicLink') {
        Remove-Item $psLink -Force
    } else {
        Write-Warning "Path $psLink exists and is not a symbolic link. Skipping to prevent data loss."
    }
}

if (-not (Test-Path $psLink)) {
    New-Item -ItemType SymbolicLink -Path $psLink -Value $psDir -Force | Out-Null
    Write-Host "Created symbolic link: $psLink -> $psDir" -ForegroundColor Green
}

# 3. Download the Profile script
try {
    Invoke-WebRequest -Uri $gistUrl -OutFile $profilePath -ErrorAction Stop
    Write-Host "Profile downloaded successfully to: $profilePath" -ForegroundColor Green
} catch {
    Write-Error "Failed to download profile: $($_.Exception.Message)"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment