# ============================================================================= # POWERSHELL PROFILE CONFIGURATION # ============================================================================= # Author: Peter Wood # Last Updated: June 17, 2025 # Description: Comprehensive PowerShell profile with enhanced functionality # # Features: # - Automatic module installation and import with error handling # - oh-my-posh prompt theming # - PSFzf fuzzy search integration # - Unix-like command aliases (grep, which, head, tail, etc.) # - Fabric AI pattern integration for text processing # - Network and system utilities # - File system helpers # - PowerShell and package management tools # - VS Code profile synchronization # # Usage: # - This profile loads automatically when starting PowerShell # - Use 'syncvscode' to sync with VS Code terminal # - Use 'Update-Profile' to reload after making changes # - All functions include help documentation accessible via Get-Help # ============================================================================= # Install missing modules Write-Host "🔍 Checking for required PowerShell modules..." -ForegroundColor Cyan if (-not (Get-Module -ListAvailable -Name Terminal-Icons)) { Write-Host "đŸ“Ļ Installing Terminal-Icons module..." -ForegroundColor Yellow try { Install-Module -Name Terminal-Icons -Scope CurrentUser -Force Write-Host "✅ Terminal-Icons installed successfully" -ForegroundColor Green } catch { Write-Error "❌ Failed to install Terminal-Icons: $($_.Exception.Message)" } } if (-not (Get-Module -ListAvailable -Name PSReadLine)) { Write-Host "đŸ“Ļ Installing PSReadLine module..." -ForegroundColor Yellow try { Install-Module -Name PSReadLine -Scope CurrentUser -Force Write-Host "✅ PSReadLine installed successfully" -ForegroundColor Green } catch { Write-Error "❌ Failed to install PSReadLine: $($_.Exception.Message)" } } if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) { Write-Host "đŸ“Ļ Installing PSScriptAnalyzer module..." -ForegroundColor Yellow try { Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser Write-Host "✅ PSScriptAnalyzer installed successfully" -ForegroundColor Green } catch { Write-Error "❌ Failed to install PSScriptAnalyzer: $($_.Exception.Message)" } } if (-not (Get-Module -ListAvailable -Name PSFzf)) { Write-Host "đŸ“Ļ Installing PSFzf module..." -ForegroundColor Yellow try { Install-Module -Name PSFzf -Scope CurrentUser -Force Write-Host "✅ PSFzf installed successfully" -ForegroundColor Green } catch { Write-Error "❌ Failed to install PSFzf: $($_.Exception.Message)" } } # Import modules Write-Host "📂 Importing PowerShell modules..." -ForegroundColor Cyan try { Import-Module -Name Terminal-Icons -ErrorAction Stop Write-Host "✅ Terminal-Icons imported successfully" -ForegroundColor Green } catch { Write-Warning "âš ī¸ Failed to import Terminal-Icons: $($_.Exception.Message)" } # Import PSReadLine with better version conflict handling if (Get-Module -Name PSReadLine) { # PSReadLine is already loaded, don't try to reimport Write-Host "✅ PSReadLine already loaded" -ForegroundColor Green } else { try { # Try to import the latest available version without forcing Import-Module -Name PSReadLine -ErrorAction Stop Write-Host "✅ PSReadLine imported successfully" -ForegroundColor Green } catch { Write-Warning "PSReadLine import failed: $($_.Exception.Message)" Write-Host "â„šī¸ Using built-in PSReadLine features" -ForegroundColor Cyan } } # Add fzf to PATH if not already there Write-Host "🔍 Checking fzf installation..." -ForegroundColor Cyan $fzfPath = "$env:LOCALAPPDATA\Microsoft\WinGet\Packages\junegunn.fzf_Microsoft.Winget.Source_8wekyb3d8bbwe" if ((Test-Path "$fzfPath\fzf.exe") -and ($env:PATH -notlike "*$fzfPath*")) { $env:PATH += ";$fzfPath" Write-Host "✅ Added fzf to PATH: $fzfPath" -ForegroundColor Green } # Also check the WinGet Links directory $wingetLinks = "$env:LOCALAPPDATA\Microsoft\WinGet\Links" if ((Test-Path "$wingetLinks\fzf.exe") -and ($env:PATH -notlike "*$wingetLinks*")) { $env:PATH += ";$wingetLinks" Write-Host "✅ Added WinGet Links to PATH: $wingetLinks" -ForegroundColor Green } # Initialize oh-my-posh prompt Write-Host "🎨 Initializing oh-my-posh prompt..." -ForegroundColor Cyan $promptTheme = "$env:OneDrive\Documents\PowerShell\prompt\themes\easy-term.omp.json" if (Test-Path $promptTheme) { try { oh-my-posh --init --shell pwsh --config $promptTheme | Invoke-Expression Write-Host "✅ oh-my-posh prompt loaded successfully" -ForegroundColor Green } catch { Write-Error "❌ Failed to load oh-my-posh prompt: $($_.Exception.Message)" } } else { Write-Warning "âš ī¸ oh-my-posh theme not found at: $promptTheme" } Write-Host "âš™ī¸ Configuring PSReadLine options..." -ForegroundColor Cyan try { Set-PSReadLineOption -PredictionSource History Set-PSReadLineOption -PredictionViewStyle ListView Set-PSReadLineOption -EditMode Windows Set-PSReadLineKeyHandler -Key Tab -Function Complete Write-Host "✅ PSReadLine configured successfully" -ForegroundColor Green } catch { Write-Warning "âš ī¸ Failed to configure PSReadLine: $($_.Exception.Message)" } # Configure PSFzf if available and fzf is installed if (Get-Command fzf -ErrorAction SilentlyContinue) { try { Import-Module -Name PSFzf -ErrorAction Stop Set-PsFzfOption -PSReadlineChordProvider 'Ctrl+f' -PSReadlineChordReverseHistory 'Ctrl+r' Write-Host "✅ PSFzf configured successfully" -ForegroundColor Green } catch { Write-Warning "Failed to configure PSFzf: $($_.Exception.Message)" } } else { Write-Host "âš ī¸ fzf binary not found in PATH. PSFzf features will be unavailable." -ForegroundColor Yellow Write-Host " Install fzf with: winget install fzf" -ForegroundColor Gray } Write-Host "🔧 Setting up command completers and additional modules..." -ForegroundColor Cyan # Register winget completion try { 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', $_) } } Write-Host "✅ winget tab completion configured" -ForegroundColor Green } catch { Write-Warning "âš ī¸ Failed to configure winget completion: $($_.Exception.Message)" } # ============================================================================= # NETWORK AND SYSTEM UTILITIES # ============================================================================= <# .SYNOPSIS Get your public IP address .DESCRIPTION Retrieves your external/public IP address by querying ifconfig.me .EXAMPLE Get-Ip-Address getIp #> function Get-Ip-Address { (Invoke-WebRequest -Uri ifconfig.me/ip).Content } Set-Alias getIp Get-Ip-Address <# .SYNOPSIS Restart WSL (Windows Subsystem for Linux) distributions .DESCRIPTION Shuts down WSL completely, which effectively restarts all running distributions .PARAMETER Distro The name of the WSL distribution to restart (defaults to 'Ubuntu') .EXAMPLE Invoke-WslReboot wslreboot wslreboot "Debian" #> function Invoke-WslReboot() { param ( [string]$Distro = 'Ubuntu' ) Write-Host "Rebooting $Distro" wsl --shutdown } Set-Alias wslreboot Invoke-WslReboot # ============================================================================= # APPLICATION AND PACKAGE MANAGEMENT # ============================================================================= <# .SYNOPSIS Update family budget database from Excel file .DESCRIPTION Runs a Python script to export budget data from an Excel spreadsheet Specific to the user's budget management workflow .EXAMPLE Update-Budget updbudget #> function Update-Budget() { Write-Host "Updating budget database" py D:\dev\export-budget-csv\export.py -s "$env:OneDrive\Documents\Financial\Wood Family Financials.xlsx" Write-Host "Budget database updated" } Set-Alias updbudget Update-Budget <# .SYNOPSIS Update all packages using winget .DESCRIPTION Runs 'winget upgrade' to update all installed packages .EXAMPLE Update-Winget wgu #> function Update-Winget() { winget upgrade } Set-Alias wgu Update-Winget #f45873b3-b655-43a6-b217-97c00aa0db58 PowerToys CommandNotFound module try { Import-Module -Name Microsoft.WinGet.CommandNotFound -ErrorAction Stop Write-Host "✅ PowerToys CommandNotFound module loaded" -ForegroundColor Green } catch { Write-Warning "âš ī¸ PowerToys CommandNotFound module not available: $($_.Exception.Message)" } #f45873b3-b655-43a6-b217-97c00aa0db58 Write-Host "đŸ—‚ī¸ Initializing zoxide (smart directory navigation)..." -ForegroundColor Cyan if (Get-Command zoxide -ErrorAction SilentlyContinue) { try { Invoke-Expression (& { (zoxide init powershell | Out-String) }) Write-Host "✅ zoxide initialized successfully" -ForegroundColor Green } catch { Write-Warning "âš ī¸ Failed to initialize zoxide: $($_.Exception.Message)" } } else { Write-Host "đŸ“Ļ zoxide not found. Attempting to install via winget..." -ForegroundColor Yellow try { winget install -e --id ajeetdsouza.zoxide Write-Host "✅ zoxide installed successfully. Initializing..." -ForegroundColor Green Invoke-Expression (& { (zoxide init powershell | Out-String) }) } catch { Write-Error "❌ Failed to install zoxide: $($_.Exception.Message)" } } # Fabric patterns integration (with error handling) Write-Host "🧩 Loading Fabric AI patterns..." -ForegroundColor Cyan try { # Path to the patterns directory $patternsPath = Join-Path $HOME ".config/fabric/patterns" if (Test-Path $patternsPath) { $patternCount = 0 foreach ($patternDir in Get-ChildItem -Path $patternsPath -Directory -ErrorAction SilentlyContinue) { $patternName = $patternDir.Name # Dynamically define a function for each pattern $functionDefinition = @" function $patternName { [CmdletBinding()] param( [Parameter(ValueFromPipeline = `$true)] [string] `$InputObject, [Parameter(ValueFromRemainingArguments = `$true)] [String[]] `$patternArgs ) begin { # Initialize an array to collect pipeline input `$collector = @() } process { # Collect pipeline input objects if (`$InputObject) { `$collector += `$InputObject } } end { # Join all pipeline input into a single string, separated by newlines `$pipelineContent = `$collector -join "`n" # If there's pipeline input, include it in the call to fabric if (`$pipelineContent) { `$pipelineContent | fabric --pattern $patternName `$patternArgs } else { # No pipeline input; just call fabric with the additional args fabric --pattern $patternName `$patternArgs } } } "@ # Add the function to the current session Invoke-Expression $functionDefinition $patternCount++ } Write-Host "✅ Loaded $patternCount Fabric patterns successfully" -ForegroundColor Green } else { Write-Host "â„šī¸ Fabric patterns directory not found at: $patternsPath" -ForegroundColor Cyan } } catch { Write-Warning "âš ī¸ Failed to load fabric patterns: $($_.Exception.Message)" } # ============================================================================= # FABRIC AI INTEGRATION FUNCTIONS # ============================================================================= <# .SYNOPSIS Get YouTube video transcript using Fabric AI .DESCRIPTION Downloads and processes YouTube video transcripts using the Fabric AI tool Can optionally include timestamps in the transcript .PARAMETER t Switch to include timestamps in the transcript .PARAMETER videoLink The YouTube video URL to process .EXAMPLE yt "https://youtube.com/watch?v=example" yt -t "https://youtube.com/watch?v=example" # With timestamps #> function yt { [CmdletBinding()] param( [Parameter()] [Alias("timestamps")] [switch]$t, [Parameter(Position = 0, ValueFromPipeline = $true)] [string]$videoLink ) begin { $transcriptFlag = "--transcript" if ($t) { $transcriptFlag = "--transcript-with-timestamps" } } process { if (-not $videoLink) { Write-Error "Usage: yt [-t | --timestamps] youtube-link" return } } end { if ($videoLink) { # Execute and allow output to flow through the pipeline fabric -y $videoLink $transcriptFlag } } } # ============================================================================= # FILE SYSTEM UTILITIES # ============================================================================= <# .SYNOPSIS Fast file finder - search for files by name pattern .DESCRIPTION Recursively searches for files matching a name pattern from current directory Similar to Unix 'find' command but simpler syntax .PARAMETER name The search pattern to match against filenames (supports wildcards) .EXAMPLE ff "*.txt" ff "config" ff "package.json" #> function ff($name) { Get-ChildItem -Recurse -Filter "*${name}*" -ErrorAction SilentlyContinue | ForEach-Object { Write-Output "$($_.Directory)\$($_.Name)" } } <# .SYNOPSIS Create an empty file (Unix-style touch command) .DESCRIPTION Creates a new empty file or updates the timestamp of an existing file Mimics the behavior of the Unix 'touch' command .PARAMETER file The path and name of the file to create or touch .EXAMPLE touch "newfile.txt" touch "C:\temp\example.log" #> function touch($file) { "" | Out-File -File $file -Encoding ascii } # ============================================================================= # PROFILE MANAGEMENT FUNCTIONS # ============================================================================= <# .SYNOPSIS Reload the current PowerShell profile .DESCRIPTION Reloads the PowerShell profile to apply any changes made to the profile file Useful for testing profile modifications without restarting the terminal .EXAMPLE Update-Profile reload-profile #> function Update-Profile { & $PROFILE } # Alias for backward compatibility Set-Alias reload-profile Update-Profile <# .SYNOPSIS Check for and install PowerShell updates .DESCRIPTION Checks GitHub for the latest PowerShell release and updates via winget if needed Includes network connectivity check to avoid unnecessary delays .EXAMPLE Update-PowerShell #> function Update-PowerShell { # Check if we can connect to GitHub with a faster, quieter method try { $response = Test-Connection -ComputerName "8.8.8.8" -Count 1 -Quiet -TimeoutSeconds 2 if (-not $response) { Write-Host "Skipping PowerShell update check - no internet connection." -ForegroundColor Yellow return } } catch { Write-Host "Skipping PowerShell update check - network unavailable." -ForegroundColor Yellow return } try { Write-Host "Checking for PowerShell updates..." -ForegroundColor Cyan $updateNeeded = $false $currentVersion = $PSVersionTable.PSVersion.ToString() $gitHubApiUrl = "https://api.github.com/repos/PowerShell/PowerShell/releases/latest" $latestReleaseInfo = Invoke-RestMethod -Uri $gitHubApiUrl $latestVersion = $latestReleaseInfo.tag_name.Trim('v') if ($currentVersion -lt $latestVersion) { $updateNeeded = $true } if ($updateNeeded) { Write-Host "Updating PowerShell..." -ForegroundColor Yellow winget upgrade "Microsoft.PowerShell" --accept-source-agreements --accept-package-agreements Write-Host "PowerShell has been updated. Please restart your shell to reflect changes" -ForegroundColor Magenta } else { Write-Host "Your PowerShell is up to date." -ForegroundColor Green } } catch { Write-Error "Failed to update PowerShell. Error: $_" } } # Commented out automatic PowerShell update check to prevent slow profile loading # Run 'Update-PowerShell' manually when you want to check for updates # Update-PowerShell # ============================================================================= # UNIX-LIKE UTILITY FUNCTIONS # ============================================================================= <# .SYNOPSIS Search for text patterns in files (Unix grep equivalent) .DESCRIPTION Searches for regex patterns in files or pipeline input Mimics the behavior of the Unix 'grep' command .PARAMETER regex The regular expression pattern to search for .PARAMETER dir Optional directory to search in (searches current dir if not specified) .EXAMPLE grep "error" *.log Get-Content file.txt | grep "pattern" grep "TODO" C:\Projects #> function grep($regex, $dir) { if ($dir) { Get-ChildItem $dir | Select-String $regex return } $input | Select-String $regex } <# .SYNOPSIS Find the location of a command (Unix which equivalent) .DESCRIPTION Locates the executable file for a given command name Mimics the behavior of the Unix 'which' command .PARAMETER command The name of the command to locate .EXAMPLE which "git" which "notepad" #> function which ($command) { Get-Command -Name $command -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path -ErrorAction SilentlyContinue } <# .SYNOPSIS Display disk usage information (Unix df equivalent) .DESCRIPTION Shows disk space usage for all mounted volumes Mimics the behavior of the Unix 'df' command .EXAMPLE df #> function df { get-volume } <# .SYNOPSIS Display the first lines of a file (Unix head equivalent) .DESCRIPTION Shows the first N lines of a text file (default: 10 lines) Mimics the behavior of the Unix 'head' command .PARAMETER Path The path to the file to read .PARAMETER n Number of lines to display (default: 10) .EXAMPLE head "file.txt" head "file.txt" 5 #> function head { param($Path, $n = 10) Get-Content $Path -Head $n } <# .SYNOPSIS Display the last lines of a file (Unix tail equivalent) .DESCRIPTION Shows the last N lines of a text file (default: 10 lines) Mimics the behavior of the Unix 'tail' command .PARAMETER Path The path to the file to read .PARAMETER n Number of lines to display (default: 10) .EXAMPLE tail "file.txt" tail "logfile.log" 20 #> function tail { param($Path, $n = 10) Get-Content $Path -Tail $n } <# .SYNOPSIS Quick navigation to Documents folder .DESCRIPTION Changes the current directory to the user's Documents folder .EXAMPLE docs #> function docs { Set-Location -Path $HOME\Documents } # ============================================================================= # NETWORKING UTILITIES # ============================================================================= <# .SYNOPSIS Flush DNS cache .DESCRIPTION Clears the DNS resolver cache to force fresh DNS lookups Useful for troubleshooting DNS issues .EXAMPLE flushdns #> function flushdns { Clear-DnsClientCache } # ============================================================================= # CLIPBOARD UTILITIES # ============================================================================= <# .SYNOPSIS Copy text to clipboard .DESCRIPTION Copies the specified text to the Windows clipboard .PARAMETER args The text to copy to clipboard .EXAMPLE cpy "Hello World" #> function cpy { Set-Clipboard $args[0] } <# .SYNOPSIS Paste text from clipboard .DESCRIPTION Retrieves text from the Windows clipboard and displays it .EXAMPLE pst #> function pst { Get-Clipboard } # Enhanced PowerShell Experience Write-Host "🎨 Configuring PowerShell color scheme..." -ForegroundColor Cyan try { Set-PSReadLineOption -Colors @{ Command = 'Yellow' Parameter = 'Green' String = 'DarkCyan' } Write-Host "✅ Color scheme applied successfully" -ForegroundColor Green } catch { Write-Warning "âš ī¸ Failed to apply color scheme: $($_.Exception.Message)" } $env:GITHUB_PERSONAL_ACCESS_TOKEN = [Environment]::GetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN", "User") # http://bin.christitus.com/unakijolon function Sync-VSCodeProfile { <# .SYNOPSIS Syncs the current PowerShell profile to VS Code .DESCRIPTION Creates or updates the VS Code PowerShell profile to source this main profile, keeping all your customizations in sync between regular PowerShell and VS Code. #> $mainProfile = $PROFILE.CurrentUserCurrentHost $vscodeProfile = $mainProfile -replace "Microsoft\.PowerShell", "Microsoft.VSCode" if (Test-Path $mainProfile) { $vscodeContent = @" # VS Code PowerShell Profile # This profile sources the main PowerShell profile to keep them in sync # Last synced: $(Get-Date) # Source the main PowerShell profile `$mainProfile = "$mainProfile" if (Test-Path `$mainProfile) { . `$mainProfile Write-Host "✅ Loaded main PowerShell profile in VS Code" -ForegroundColor Green } else { Write-Warning "Main PowerShell profile not found at: `$mainProfile" } # VS Code specific customizations can go here if needed "@ Set-Content -Path $vscodeProfile -Value $vscodeContent -Encoding UTF8 Write-Host "✅ VS Code profile synced successfully!" -ForegroundColor Green Write-Host "Location: $vscodeProfile" -ForegroundColor Cyan } else { Write-Error "Main PowerShell profile not found at: $mainProfile" } } Set-Alias syncvscode Sync-VSCodeProfile # Profile loading complete Write-Host "" # Empty line for spacing Write-Host "🎉 PowerShell profile loaded successfully!" -ForegroundColor Green Write-Host " Type 'Get-Help about_profiles' for more information" -ForegroundColor Gray Write-Host " Use 'syncvscode' to sync this profile with VS Code" -ForegroundColor Gray