Created
May 15, 2025 19:43
-
-
Save wchesley/191ecb6f430ab88f89bbcd4b2b5258e7 to your computer and use it in GitHub Desktop.
Powershell 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
| ####################################################################### | |
| # Powershell profile for Walker Chesley | |
| # Last Updated: 2025-05-15 | |
| ####################################################################### | |
| Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force | |
| # Module imports | |
| Import-Module -Name PSReadLine -Force | |
| Import-Module Terminal-Icons -Force | |
| Import-Module posh-git | |
| # Import the Chocolatey Profile that contains the necessary code to enable | |
| # tab-completions to function for `choco`. | |
| # Be aware that if you are missing these lines from your profile, tab completion | |
| # for `choco` will not function. | |
| # See https://ch0.co/tab-completion for details. | |
| $ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" | |
| if (Test-Path($ChocolateyProfile)) { | |
| Import-Module "$ChocolateyProfile" | |
| } | |
| # Shell UI customization | |
| $shell = $Host.UI.RawUI | |
| $identity = [Security.Principal.WindowsIdentity]::GetCurrent() | |
| $shell.WindowTitle = $identity.Name + " - Powershell" | |
| oh-my-posh --init --shell pwsh --config ./kali.omp.json | Invoke-Expression | |
| # Aliases | |
| Set-Alias which Get-Command | |
| Set-Alias touch New-Item | |
| Set-Alias Invoke-WebRequest curl.exe | |
| Set-Alias -Name grep -Value Findstr | |
| # Customize PSReadLine | |
| Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete | |
| Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward | |
| Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward | |
| Set-PsReadLinkKeyHandler -Key Ctrl+a -Function BeginningOfLine | |
| Set-PsReadLinkKeyHandler -Key Ctrl+e -Function EndOfLine | |
| Set-PSReadlineOption -HistorySearchCursorMovesToEnd | |
| Set-PSReadlineOption -ShowToolTips | |
| Set-PSReadlineOption -PredictionSource History | |
| Set-PSReadLineOption -PredictionViewStyle ListView | |
| (Get-PSReadLineOption).HistoryNoDuplicates = $False | |
| (Get-PSReadLineOption).HistorySearchCaseSensitive = $False | |
| (Get-PSReadLineOption).HistorySearchCursorMovesToEnd = $True | |
| (Get-PSReadLineOption).ShowToolTips = $True | |
| (Get-PSReadLineOption).EditMode = "Vi" | |
| ## Functions: | |
| ## Customize the prompt for admin or regular user: | |
| function prompt { | |
| $identity = [Security.Principal.WindowsIdentity]::GetCurrent() | |
| $principal = [Security.Principal.WindowsPrincipal] $identity | |
| $adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator | |
| $prefix = if (Test-Path variable:/PSDebugContext) { '[DBG]: ' } else { '' } | |
| if ($principal.IsInRole($adminRole)) { | |
| $prefix = "[ADMIN]:$prefix" | |
| } | |
| $body = 'PS ' + $PWD.path | |
| $suffix = $(if ($NestedPromptLevel -ge 1) { '>>' }) + '> ' | |
| "${prefix}${body}${suffix}" | |
| } | |
| ## Reload profile function: | |
| function reload { | |
| & $profile | |
| } | |
| ## Get current public IP: | |
| Function PubIp { | |
| curl.exe 'https://icanhazip.com' | |
| } | |
| ## Get system uptime function: | |
| function uptime { | |
| Get-WmiObject win32_operatingsystem | select csname, @{LABEL='LastBootUpTime'; | |
| EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}} | |
| } | |
| ## Add argument completer for the dotnet CLI tool | |
| $scriptblock = { | |
| param($wordToComplete, $commandAst, $cursorPosition) | |
| dotnet complete --position $cursorPosition $commandAst.ToString() | | |
| ForEach-Object { | |
| [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) | |
| } | |
| } | |
| Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock | |
| #region Smart Insert/Delete | |
| # The next four key handlers are designed to make entering matched quotes | |
| # parens, and braces a nicer experience. I'd like to include functions | |
| # in the module that do this, but this implementation still isn't as smart | |
| # as ReSharper, so I'm just providing it as a sample. | |
| Set-PSReadLineKeyHandler -Key '"',"'" ` | |
| -BriefDescription SmartInsertQuote ` | |
| -LongDescription "Insert paired quotes if not already on a quote" ` | |
| -ScriptBlock { | |
| param($key, $arg) | |
| $quote = $key.KeyChar | |
| $selectionStart = $null | |
| $selectionLength = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) | |
| $line = $null | |
| $cursor = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) | |
| # If text is selected, just quote it without any smarts | |
| if ($selectionStart -ne -1) | |
| { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $quote + $line.SubString($selectionStart, $selectionLength) + $quote) | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) | |
| return | |
| } | |
| $ast = $null | |
| $tokens = $null | |
| $parseErrors = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$parseErrors, [ref]$null) | |
| function FindToken | |
| { | |
| param($tokens, $cursor) | |
| foreach ($token in $tokens) | |
| { | |
| if ($cursor -lt $token.Extent.StartOffset) { continue } | |
| if ($cursor -lt $token.Extent.EndOffset) { | |
| $result = $token | |
| $token = $token -as [StringExpandableToken] | |
| if ($token) { | |
| $nested = FindToken $token.NestedTokens $cursor | |
| if ($nested) { $result = $nested } | |
| } | |
| return $result | |
| } | |
| } | |
| return $null | |
| } | |
| $token = FindToken $tokens $cursor | |
| # If we're on or inside a **quoted** string token (so not generic), we need to be smarter | |
| if ($token -is [StringToken] -and $token.Kind -ne [TokenKind]::Generic) { | |
| # If we're at the start of the string, assume we're inserting a new string | |
| if ($token.Extent.StartOffset -eq $cursor) { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote ") | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) | |
| return | |
| } | |
| # If we're at the end of the string, move over the closing quote if present. | |
| if ($token.Extent.EndOffset -eq ($cursor + 1) -and $line[$cursor] -eq $quote) { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) | |
| return | |
| } | |
| } | |
| if ($null -eq $token -or | |
| $token.Kind -eq [TokenKind]::RParen -or $token.Kind -eq [TokenKind]::RCurly -or $token.Kind -eq [TokenKind]::RBracket) { | |
| if ($line[0..$cursor].Where{$_ -eq $quote}.Count % 2 -eq 1) { | |
| # Odd number of quotes before the cursor, insert a single quote | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote) | |
| } | |
| else { | |
| # Insert matching quotes, move cursor to be in between the quotes | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote") | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) | |
| } | |
| return | |
| } | |
| # If cursor is at the start of a token, enclose it in quotes. | |
| if ($token.Extent.StartOffset -eq $cursor) { | |
| if ($token.Kind -eq [TokenKind]::Generic -or $token.Kind -eq [TokenKind]::Identifier -or | |
| $token.Kind -eq [TokenKind]::Variable -or $token.TokenFlags.hasFlag([TokenFlags]::Keyword)) { | |
| $end = $token.Extent.EndOffset | |
| $len = $end - $cursor | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Replace($cursor, $len, $quote + $line.SubString($cursor, $len) + $quote) | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($end + 2) | |
| return | |
| } | |
| } | |
| # We failed to be smart, so just insert a single quote | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote) | |
| } | |
| Set-PSReadLineKeyHandler -Key '(','{','[' ` | |
| -BriefDescription InsertPairedBraces ` | |
| -LongDescription "Insert matching braces" ` | |
| -ScriptBlock { | |
| param($key, $arg) | |
| $closeChar = switch ($key.KeyChar) | |
| { | |
| <#case#> '(' { [char]')'; break } | |
| <#case#> '{' { [char]'}'; break } | |
| <#case#> '[' { [char]']'; break } | |
| } | |
| $selectionStart = $null | |
| $selectionLength = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) | |
| $line = $null | |
| $cursor = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) | |
| if ($selectionStart -ne -1) | |
| { | |
| # Text is selected, wrap it in brackets | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $key.KeyChar + $line.SubString($selectionStart, $selectionLength) + $closeChar) | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) | |
| } else { | |
| # No text is selected, insert a pair | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)$closeChar") | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) | |
| } | |
| } | |
| Set-PSReadLineKeyHandler -Key ')',']','}' ` | |
| -BriefDescription SmartCloseBraces ` | |
| -LongDescription "Insert closing brace or skip" ` | |
| -ScriptBlock { | |
| param($key, $arg) | |
| $line = $null | |
| $cursor = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) | |
| if ($line[$cursor] -eq $key.KeyChar) | |
| { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1) | |
| } | |
| else | |
| { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)") | |
| } | |
| } | |
| Set-PSReadLineKeyHandler -Key Backspace ` | |
| -BriefDescription SmartBackspace ` | |
| -LongDescription "Delete previous character or matching quotes/parens/braces" ` | |
| -ScriptBlock { | |
| param($key, $arg) | |
| $line = $null | |
| $cursor = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) | |
| if ($cursor -gt 0) | |
| { | |
| $toMatch = $null | |
| if ($cursor -lt $line.Length) | |
| { | |
| switch ($line[$cursor]) | |
| { | |
| <#case#> '"' { $toMatch = '"'; break } | |
| <#case#> "'" { $toMatch = "'"; break } | |
| <#case#> ')' { $toMatch = '('; break } | |
| <#case#> ']' { $toMatch = '['; break } | |
| <#case#> '}' { $toMatch = '{'; break } | |
| } | |
| } | |
| if ($toMatch -ne $null -and $line[$cursor-1] -eq $toMatch) | |
| { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2) | |
| } | |
| else | |
| { | |
| [Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg) | |
| } | |
| } | |
| } | |
| #endregion Smart Insert/Delete | |
| # F1 for help on the command line - naturally | |
| Set-PSReadLineKeyHandler -Key F1 ` | |
| -BriefDescription CommandHelp ` | |
| -LongDescription "Open the help window for the current command" ` | |
| -ScriptBlock { | |
| param($key, $arg) | |
| $ast = $null | |
| $tokens = $null | |
| $errors = $null | |
| $cursor = $null | |
| [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor) | |
| $commandAst = $ast.FindAll( { | |
| $node = $args[0] | |
| $node -is [CommandAst] -and | |
| $node.Extent.StartOffset -le $cursor -and | |
| $node.Extent.EndOffset -ge $cursor | |
| }, $true) | Select-Object -Last 1 | |
| if ($commandAst -ne $null) | |
| { | |
| $commandName = $commandAst.GetCommandName() | |
| if ($commandName -ne $null) | |
| { | |
| $command = $ExecutionContext.InvokeCommand.GetCommand($commandName, 'All') | |
| if ($command -is [AliasInfo]) | |
| { | |
| $commandName = $command.ResolvedCommandName | |
| } | |
| if ($commandName -ne $null) | |
| { | |
| Get-Help $commandName -ShowWindow | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment