Skip to content

Instantly share code, notes, and snippets.

@eggbean
Last active February 22, 2025 17:56
Show Gist options
  • Save eggbean/81e7d1be5e7302c281ccc9b04134949e to your computer and use it in GitHub Desktop.
Save eggbean/81e7d1be5e7302c281ccc9b04134949e to your computer and use it in GitHub Desktop.
PowerShell $profile which automatically updates in the background when a new version number appears in this gist.
# Version 1.7.0
$gistUrl = "https://api.github.com/gists/81e7d1be5e7302c281ccc9b04134949e"
$gistFileName = '$profile' # Change this to match the filename in your Gist
$checkInterval = 4 # Check for updates every 4 hours
$updateCheckFile = [System.IO.Path]::Combine($HOME, ".profile_update_check")
$versionRegEx = "# Version (?<version>\d+\.\d+\.\d+)"
$localProfilePath = $Profile.CurrentUserCurrentHost
# Last update check timestamp
if (-not $env:PROFILE_LAST_CHECK) {
if (Test-Path $updateCheckFile) {
$env:PROFILE_LAST_CHECK = (Get-Content -Path $updateCheckFile -Raw).Trim()
} else {
$env:PROFILE_LAST_CHECK = (Get-Date).AddHours(-($checkInterval + 1)).ToString("yyyy-MM-dd HH:mm:ss")
}
}
# Start a background job to check for and apply updates if necessary
if ([datetime]::ParseExact($env:PROFILE_LAST_CHECK, "yyyy-MM-dd HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture).AddHours($checkInterval) -lt (Get-Date)) {
Start-Job -ScriptBlock {
param ($gistUrl, $gistFileName, $versionRegEx, $updateCheckFile, $localProfilePath)
try {
$gist = Invoke-RestMethod -Uri $gistUrl -ErrorAction Stop
$gistProfileContent = $gist.Files[$gistFileName].Content
if (-not $gistProfileContent) {
return
}
$gistVersion = $null
if ($gistProfileContent -match $versionRegEx) {
$gistVersion = $matches.Version
} else {
return
}
$currentVersion = "0.0.0"
if (Test-Path $localProfilePath) {
$currentProfileContent = Get-Content -Path $localProfilePath -Raw
if ($currentProfileContent -match $versionRegEx) {
$currentVersion = $matches.Version
}
}
if ([version]$gistVersion -gt [version]$currentVersion) {
Set-Content -Path $localProfilePath -Value $gistProfileContent -Encoding UTF8
}
Set-Content -Path $updateCheckFile -Value (Get-Date -Format "yyyy-MM-dd HH:mm:ss").Trim()
} catch {
# Suppress errors to avoid interfering with shell startup
}
} -ArgumentList $gistUrl, $gistFileName, $versionRegEx, $updateCheckFile, $localProfilePath | Out-Null
}
# Set the execution policy for the current user
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
# Environment variable for
# custom vim colour scheme
$env:MYSHELL = 'powershell'
# Environment setup
$binPath = Join-Path $env:USERPROFILE "winfiles\bin"
$scriptsPath = Join-Path $env:USERPROFILE "winfiles\scripts"
if (-not $env:Path.Contains($binPath)) { $env:Path = "$binPath;$env:Path" }
if (-not $env:Path.Contains($scriptsPath)) { $env:Path = "$scriptsPath;$env:Path" }
# PSReadline
Import-Module PSReadLine
Set-PSReadLineOption -EditMode Emacs -ShowToolTips
Set-PSReadLineKeyHandler -Chord F2 -Function SwitchPredictionView
Set-PSReadLineKeyHandler -Chord Shift+Tab -Function MenuComplete
# List of aliases to remove
# (using unix tools instead: scoop install uutils-coreutils)
$aliases = @('cat', 'cp', 'diff', 'ls', 'mv', 'rm', 'rmdir', 'wget')
foreach ($alias in $aliases) {
$aliasPath = "Alias:$alias"
if (Test-Path $aliasPath) {
Remove-Item $aliasPath -Force
}
}
# Aliases
Set-Alias vi vim
Set-Alias tree tre
Set-Alias cat ccat
Set-Alias props GDProps.exe
Set-Alias wget wget2
Set-Alias br broot
Set-Alias wol WakeMeOnLan
Set-Alias battery batteryinfoview
Set-Alias qutebrowser "C:\Program Files\qutebrowser\qutebrowser.exe"
Set-Alias qb qutebrowser
# CopyQ
function copyq {
& "C:\Program Files\CopyQ\copyq.exe" @Args | Out-Host -Paging
}
# gsudo
Import-Module gsudoModule
Set-Alias sudo gsudo
# Faster scoop search
Invoke-Expression (&scoop-search --hook)
# Vimdiff
function vimdiff {
& vim -d @args
}
# Make directory and cd to it, with pushd for CD Deluxe
function take {
param($1)
mkdir $1 | Out-Null
Push-Location $PWD
Set-Location $1
}
# Turn monitor off
function screenoff {
& nircmd monitor async_off
}
# Zoxide function to add current location
function za {
zoxide add (Get-Location).Path
}
# Initialise zoxide without auto-defining its commands
Invoke-Expression (& { (zoxide init --no-cmd powershell | Out-String) })
# Define the `z` function with pushd behavior for CD Deluxe
function z {
param (
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $Args
)
Push-Location $PWD
__zoxide_z @Args
}
# Define the `zi` function with pushd behavior for CD Deluxe
function zi {
param (
[Parameter(ValueFromRemainingArguments = $true)]
[string[]] $Args
)
Push-Location $PWD
__zoxide_zi @Args
}
# CD Deluxe
# https://github.com/m6z/cd-deluxe
function cdd {
param(
[Parameter(ValueFromRemainingArguments=$true)]
[string[]]$Arguments
)
$dest = if ($Arguments) { $Arguments -join ' ' }
if ($dest -and $dest.StartsWith('~')) {
$dest = $HOME + $dest.Substring(1)
$Arguments = @($dest)
}
$dirStack = Get-Location -Stack | ForEach-Object { $_.Path }
$result = $dirStack | & "$env:USERPROFILE\winfiles\bin\_cdd.exe" @Arguments
if ($result -match '^pushd\s+(.+)$') {
Push-Location $matches[1]
}
elseif ($result -and (Test-Path $result)) {
Set-Location $result
}
else {
Write-Host $result
}
}
Remove-Item alias:cd -Force -ErrorAction SilentlyContinue
Set-Alias -Name cd -Value cdd -Option AllScope
# Function to make eza work like ls (work in progress)
function ls {
# Default settings for options
$dot = $true # Don't list implied . and .. by default with -a
$hru = $true # Show human-readable file sizes by default
$meb = $false # File sizes in binary (false) or decimal (true)
$fgp = $false # Don't show group column
$lnk = $false # Don't show hardlinks column
$git = $true # Always show git status when available
$ico = $false # Don't show icons
$hed = $false # Don't show column headers
$gpd = $false # Don't group directories first
$col = $true # Always use color even when piping
# eza options list
$eza_opts = @()
# Manual parsing of arguments for case sensitivity
$i = 0
while ($i -lt $args.Length) {
$arg = $args[$i]
# Handle flags and options manually
if ($arg -ceq '-a') {
if ($dot) {
$eza_opts += '-a'
} else {
$eza_opts += ('-a', '-a')
}
} elseif ($arg -ceq '-A') {
$eza_opts += '-a'
} elseif ($arg -ceq '-l') {
$eza_opts += '-l' # Long listing format
} elseif ($arg -ceq '-L') {
$i++
if ($i -lt $args.Length) {
$eza_opts += "--level=$($args[$i])"
} else {
Write-Error "-L requires a value"
return
}
} elseif ($arg -ceq '-t') {
$eza_opts += ('-s', 'modified')
} elseif ($arg -ceq '-u') {
$eza_opts += ('-us', 'accessed')
} elseif ($arg -ceq '-c') {
$eza_opts += ('-Us', 'created')
} elseif ($arg -ceq '-S') {
$eza_opts += ('-s', 'size')
} elseif ($arg -ceq '-I') {
$i++
if ($i -lt $args.Length) {
$eza_opts += "--ignore-glob=$($args[$i])"
} else {
Write-Error "-I requires a value"
return
}
} elseif ($arg -ceq '-r') {
$eza_opts += '-r'
} elseif ($arg -ceq '-k') {
$hru = $false
} elseif ($arg -ceq '-h') {
$hru = $true
} elseif ($arg -ceq '-n') {
$eza_opts += '--git-ignore'
} elseif ($arg -ceq '-s') {
$eza_opts += '-S'
} elseif ($arg -ceq '-X') {
$eza_opts += ('-s', 'extension')
} elseif ($arg -ceq '-M') {
$i++
if ($i -lt $args.Length) {
$eza_opts += "--time-style=$($args[$i])"
} else {
Write-Error "-M requires a value"
return
}
} elseif ($arg -ceq '-P') {
$gpd = $true
} elseif ($arg -ceq '-N') {
$col = $false
} elseif ($arg -ceq '-g') {
$git = $true
} elseif ($arg -ceq '-O') {
$ico = $true
} elseif ($arg -ceq '-b') {
$meb = $false
} elseif ($arg -ceq '-1') {
$eza_opts += '-1'
} elseif ($arg -ceq '-F') {
$eza_opts += '-F'
} elseif ($arg -ceq '-G') {
$eza_opts += '-G'
} elseif ($arg -ceq '-R') {
$eza_opts += '-R'
} elseif ($arg -ceq '-d') {
$eza_opts += '-d'
} elseif ($arg -ceq '-D') {
$eza_opts += '-D'
} elseif ($arg -ceq '-i') {
$eza_opts += '-i'
} elseif ($arg -ceq '-T') {
$eza_opts += '-T'
} elseif ($arg -ceq '-x') {
$eza_opts += '-x'
} elseif ($arg -ceq '-Z') {
$eza_opts += '-Z'
} elseif ($arg -ceq '-@') {
$eza_opts += '-@'
} elseif ($arg -ceq '--help') {
@"
ls (eza wrapper) options:
-a all
-A almost all
-1 one file per line
-x list by lines, not columns
-l long listing format
-G display entries as a grid
-k bytes
-h human-readable file sizes
-F classify
-R recurse
-r reverse
-d don't list directory contents
-D directories only
-P group directories first
-I ignore [GLOBS]
-i show inodes
-o show octal permissions
-N no color
-S sort by file size
-t sort by modified time
-u sort by accessed time
-c sort by created time
-X sort by extension
-M time style [iso|long-iso|full-iso|relative]
-T tree
-L level [DEPTH]
-s file system blocks
-g don't show/show file git status
-O don't show/show icons
-n ignore .gitignore files
-b file sizes in binary/decimal (--si in ls)
-Z show each file's security context
-@ extended attributes and sizes
"@
return
} else {
# Pass through unrecognized arguments
$eza_opts += $arg
}
$i++
}
# Apply defaults for options not set
if (-not $hru) { $eza_opts += '-B' }
if ($col) { $eza_opts += '--color=always' } else { $eza_opts += '--color=auto' }
if ($gpd) { $eza_opts += '--group-directories-first' }
if ($ico) { $eza_opts += '--icons' }
if ($git) { $eza_opts += '--git' } # Always include --git if $git is true
# Run eza with constructed options
eza @eza_opts
}
function ll { & ls -l @args }
# Starship
Invoke-Expression (&starship init powershell)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment