Skip to content

Instantly share code, notes, and snippets.

@bugged-codes
Last active February 24, 2023 14:37
Show Gist options
  • Save bugged-codes/5b8c7e835fd7bbfc4d92920c955a7bc2 to your computer and use it in GitHub Desktop.
Save bugged-codes/5b8c7e835fd7bbfc4d92920c955a7bc2 to your computer and use it in GitHub Desktop.
Customized Powershell Profile
# powershell profile is located at %userporfile%/documents/PowerShell/Microsoft.PowerShell_profile.ps1
using namespace System.Management.Automation
using namespace System.Management.Automation.Language
# PSReadLine
Import-Module PSReadLine
Set-PSReadLineKeyHandler -key Tab -Function Complete
Set-PSReadLineOption -PredictionSource History
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -EditMode Windows
#PSReadLine Custom Options taken from Scott Hanselman's powershell and tim sneath gists.
# This key handler shows the entire or filtered history using Out-GridView. The typed text is used as the substring pattern for filtering.
#A selected command is inserted to the command line without invoking. Multiple command selection is supported, e.g. selected by Ctrl + Click.
Set-PSReadLineKeyHandler -Key F7 `
-BriefDescription History `
-LongDescription 'Show command history' `
-ScriptBlock {
$pattern = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$pattern, [ref]$null)
if ($pattern)
{
$pattern = [regex]::Escape($pattern)
}
$history = [System.Collections.ArrayList]@(
$last = ''
$lines = ''
foreach ($line in [System.IO.File]::ReadLines((Get-PSReadLineOption).HistorySavePath))
{
if ($line.EndsWith('`'))
{
$line = $line.Substring(0, $line.Length - 1)
$lines = if ($lines)
{
"$lines`n$line"
}
else
{
$line
}
continue
}
if ($lines)
{
$line = "$lines`n$line"
$lines = ''
}
if (($line -cne $last) -and (!$pattern -or ($line -match $pattern)))
{
$last = $line
$line
}
}
)
$history.Reverse()
$command = $history | Out-GridView -Title History -PassThru
if ($command)
{
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(($command -join "`n"))
}
}
# 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)
}
}
}
# 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
}
}
}
}
### Tim sneaths profile
### From https://gist.github.com/timsneath/19867b12eee7fd5af2ba
###
### As a reminder, to enable unsigned script execution of local scripts on client Windows,
### you need to run this line (or similar) from an elevated PowerShell prompt:
### Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
### This is the default policy on Windows Server 2012 R2 and above for server Windows. For
### more information about execution policies, run Get-Help about_Execution_Policies.
# Find out if the current user identity is elevated (has admin rights)
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal $identity
$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
# If so and the current host is a command line, then change to red color
# as warning to user that they are operating in an elevated context
if (($host.Name -match "ConsoleHost") -and ($isAdmin))
{
$host.UI.RawUI.BackgroundColor = "DarkRed"
$host.PrivateData.ErrorBackgroundColor = "White"
$host.PrivateData.ErrorForegroundColor = "DarkRed"
Clear-Host
}
# Useful shortcuts for traversing directories
function cd... { cd ..\.. }
function cd.... { cd ..\..\.. }
# Compute file hashes - useful for checking successful downloads
function md5 { Get-FileHash -Algorithm MD5 $args }
function sha1 { Get-FileHash -Algorithm SHA1 $args }
function sha256 { Get-FileHash -Algorithm SHA256 $args }
# Set up command prompt and window title. Use UNIX-style convention for identifying
# whether user is elevated (root) or not. Window title shows current version of PowerShell
# and appends [ADMIN] if appropriate for easy taskbar identification
function prompt
{
if ($isAdmin)
{
"[" + (Get-Location) + "] # "
}
else
{
"[" + (Get-Location) + "] $ "
}
}
$Host.UI.RawUI.WindowTitle = "PowerShell {0}" -f $PSVersionTable.PSVersion.ToString()
if ($isAdmin)
{
$Host.UI.RawUI.WindowTitle += " [ADMIN]"
}
# Simple function to start a new elevated process. If arguments are supplied then
# a single command is started with admin rights; if not then a new admin instance
# of PowerShell is started.
function admin
{
if ($args.Count -gt 0)
{
$argList = "& '" + $args + "'"
Start-Process "pwsh" -Verb runAs -ArgumentList $argList
}
else
{
Start-Process "pwsh" -Verb runAs
}
}
# Set UNIX-like aliases for the admin command, so sudo <command> will run the command
# with elevated rights.
Set-Alias -Name su -Value admin
Set-Alias -Name sudo -Value admin
# We don't need these any more; they were just temporary variables to get to $isAdmin.
# Delete them to prevent cluttering up the user profile.
Remove-Variable identity
Remove-Variable principal
# Oh-My-Posh settings
<# Install OMP:
winget install JanDeDobbeleer.OhMyPosh -s winget
#>
# Created variables for OMP theme.
# In order to change theme just change .json theme in $OMPThemePath
$OMPThemesFolder = $($env:APPDATA)+'\..\Local\Programs\oh-my-posh\themes\'
$OMPThemePath = $OMPThemesFolder + 'powerlevel10k_rainbow.omp.json'
oh-my-posh init pwsh --config $OMPThemePath | Invoke-Expression
# Terminal Icons
Import-Module -Name Terminal-Icons
# this is single line comment
<# Block-Comment
To change theme, replace name of the theme with the one you want to install, i.e. the word after ..\themes\ and keep extension as ".omp.json"
After changing theme, apply the current profile by giving ".$PROFILE" command in powershell.
My Favoriate themes:
1. tokyo
2. quick-term
3. emodipt-extend
4. slim
5. space
6. plague
7. powerlevel10k_rainbow
8. montys
9. kushal
Install **file type icons** type command:
Install-Module -Name Terminal-Icons -Repository PSGallery
and then add following command to profile file of powershell:
Import-Module -Name Terminal-Icons
To install Z use coommand:
install-module -name z -force
To install PSReadLine:
install-module -name PSReadLine -AllowPrerelese -scope CurrentUser -force -SkipPublisherCheck
Options for PSReadLine:
set-PSReadLineOption -PredictionSource History
restart terminal/shell
set-PSReadLineOption -PredictionViewStyle ListView
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment