cheatsheet-powershell
Table of Contents
Cheatsheet PowerShell
Summary: Powershell hints, tips, oneliners and best practices.
Date: 8 December 2024
Useful links
PowerShell Help
Get-Help with -Parameter is a quick way to examine the data type a given parameter expects:PS> Get-Help Get-ChildItem -Parameter Path -Path <String[]> Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (`.`). Required? false Position? 0 Default value Current directory Accept pipeline input? True (ByPropertyName, ByValue) Accept wildcard characters? false
PowerShell History
View history of powershell commands and invoke them using “r #”
Get-History <# Output #> r 1
See all saved commands in vscodecode (Get-PSReadLineOption).HistorySavePath
PowerShell If
If statementif (($alllogs -eq "True") -AND ($result)){ Write-Host "Both statements are true" }elseif (($buildreason -eq "IndividualCI") -or ($buildreason -eq "BatchedCI") -or ($buildreason -eq "PullRequest")){ Write-Host "At least one of the statements is true" }else { Write-Host "None of the statements is true" }
PowerShell Count
Count number of strings / objects# string $een = "een" $een.Count 1 # Array $twee = @("een","twee") $twee.count 2
Length# string $een = "een" $een.Length 3 # Array $twee = @("een","twee") $twee.Length 2 $twee[0].Length 3
Measure-Object - Sometimes counting when there is only one item can fail, use measure-object instead.$een = "een" ($een | Measure-Object).Count 1 $twee = @("een","twee") ($twee | Measure-Object).Count 2
PowerShell Dates
# Dates $timestamp = Get-Date -format "yyyyMMdd-HH.mm" # 20211011-14.27 $readdate = Get-Date -format "d MMM yyyy" # 11 Oct 2021 $weekdate = Get-Date -uformat %V # Week number # 41 $monthdate = Get-Date -format "MMMM-yyyy" # May-2021
add or subtract days[datetime]$endDate = (Get-Date).AddDays(+90) [datetime]$endDate = (Get-Date).AddDays(-90)
Powershell Error Handling
Error handling explained
Try Catch Error Finally with LineNumber for troubleshooting
function Get-ScriptLineNumber { return $MyInvocation.ScriptLineNumber } try{ Write-Host "Do something that you want to catch the error of" }catch{ # Catch the error Write-Host "Full Error: $_" # Or error out after all Throw "Failed on: $actionname; Status: Failed; Line: $(Get-ScriptLineNumber); Error: $($_.Exception.Message)" }finally { <#Do this after the try block regardless of whether an exception occurred or not#> # For example, clean up remote ps sessions }
Exception.optionstry{ # Do something that you want to catch the error of Get-ChildItem \\prox-hyperv -ErrorAction Stop # [System.Net.DNS]::GetHostByName("server99") # Connect-AzAccount # Get-AzResourceGroup -Name "exampleGroup" -ErrorAction Stop }catch [System.Management.Automation.ItemNotFoundException] { Write-Host "Cannot find item." Write-Host -NoNewLine "Exception Message : " Write-Host -Foreground Red -Background Black "$($_.Exception.Message)" }catch{ # Catch the error Write-Host -Foreground Red -Background Black "Error found. Please try again, or if the error persists, contact support for evaluation. Please provide the following diagnostics:" Write-Host -NoNewLine "Exception Message : " Write-Host -Foreground Red -Background Black "$($_.Exception.Message)" # Exceptions can contain inner exceptions. This is often the case when the code you are calling catches an exception and throws a different exception. They will place the original exception inside the new exception. Write-Host -NoNewLine "Inner Exception Message : " Write-Host -Foreground Red -Background Black "$($_.Exception.InnerException.Message)" # The FullyQualifiedErrorId is the .Message property of the exception object along with the the fully-qualified name of the class where the exception originated. Write-Host -NoNewLine "Fully Qualified Error Id : " Write-Host -Foreground Red -Background Black "$($_.FullyQualifiedErrorId)" # Output provides the error type you need to catch this specific error type Write-Host -NoNewLine "Exception type : " Write-Host -Foreground Red -Background Black "$($_.Exception.GetType().fullname)" # Shows the powershell command. Does not work for .Net exceptions Write-Host -NoNewLine "Command : " Write-Host -Foreground Red -Background Black "$($_.InvocationInfo.MyCommand)" # Position of the error in the scriptblock or file Write-Host -NoNewLine "Position : " Write-Host -Foreground Red -Background Black "At line: $($_.InvocationInfo.ScriptLineNumber) char:$($_.InvocationInfo.OffsetInLine)" # Shows the faulty line. Also works for .Net exceptions Write-Host -NoNewLine "Full line : " Write-Host -Foreground Red -Background Black "$($_.InvocationInfo.Line)" # Shows the full error. Useful for troubleshooting. Provides output so use careful when returning output. Write-Host "Full Error:" Get-Error # Shows the full error for AZ cmdlets. Useful for troubleshooting. Provides output so use careful when returning output. Usually also works with non AZ cmdlets. Write-Host "Full Azure Error:" Resolve-AzError -Last }finally { #Do this after the try block regardless of whether an exception occurred or not. For example, clean up remote ps sessions, clear variables or cleanup files. }
PowerShell Input and Output
Enable logging of script
### Script Variables ### $scriptname = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString()) $scriptlocation = Split-Path $myinvocation.mycommand.path $date = (Get-Date).ToString('yyyyMMdd-HHmm') ### Start transcript for full logging capabilities ### start-transcript -path "$scriptlocation\$scriptname-$date-logtranscript.txt" ### Stop transcript Stop-transcript
Script output and Write-Host options
# Inside a function use return or write-output return "value" Write-Output $value # Output an object without adding it to the function output Write-Host "color" -ForegroundColor Red -BackgroundColor green -noNewLine $object | Out-Host
Input password$password = Read-Host "Enter password" -asSecureString
Use padright to fill a line with one symbolWrite-Host ''.PadRight(78, '=') # Or with a variable $wide = 32 Write-Host ''.PadRight($wide, '=')
Preference Variables
Verbose Preference# Default $VerbosePreference = 'SilentlyContinue' # Override: -Verbose # Verbose output $VerbosePreference = 'Continue' # Override: -Verbose:$false
Debug Preference# Default $DebugPreference = 'SilentlyContinue' # Debug output $DebugPreference = 'Continue'
Whatif Preference# Default $WhatIfPreference = $false # Override: -WhatIf # When WhatIf is enabled, the cmdlet reports the expected effect of the command, but doesn't execute the command. $WhatIfPreference = $true # Override: -WhatIf:$false
PowerShell Variables
Set system (environment) variable$env:var="value"
Get all system (environment) variables, sorted by nameget-childitem -path env:* | Sort Name
Variables in function
Declare a variable with script scope to use it in a function$script:orgUrl = "https://dev.azure.com/getshiftingcom" $script:apiversion = "api-version=6.0" function SetBuildTag { # Load Azure DevOps API settings AzureDevOpsAPISettings foreach ($tag in $tags){ $tagurl = "$orgUrl/$env:System_Teamproject/_apis/build/builds/$env:BUILD_BUILDID/tags/$($tag)?$apiversion" } }
set variable with a dash/hyphenNew-Variable -Name "MODULE-SiteName" -Value "Incomingapi"
set system variable with a dash/hyphen[Environment]::SetEnvironmentVariable('MODULE-SiteName','Incomingapi')
Set system variables with a dash/hyphen${env:test-app_user} = "svc-test-dev" $user = ${env:test-app_user}
Remote PowerShell
Set variables
$AdminCredentials = Get-Credential $remotePort = 5986 $pso = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck $Culture = "en-US" $pso.Culture = $Culture $pso.UICulture = $Culture $sessionParams = @{} $sessionParams.Add('UseSSL', $true) $sessionParams.Add('Port', $remotePort) $sessionParams.Add('Credential', $AdminCredentials)
Start session to restart computer$session = New-PSSession -ComputerName webserverdmz.domain -EnableNetworkAccess -SessionOption $pso @sessionParams Invoke-Command -Session $session -ScriptBlock {Restart-Computer} Remove-PSSession $session
PowerShell Function Template
See here for guidelines.
function Use-AzureDevOpsApi{ #Use Get-Verb for a list of approved verbs <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Pat Explain the parameter Pat. Repeat for additional parameters. .OUTPUTS Explain the powershell output, if any .EXAMPLE Pipeline example: - task: PowerShell@2 displayName: "Use Default SystemAccessToken" env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) inputs: pwsh: true targetType: 'inline' script: | # Load Azure DevOps API settings Use-AzureDevOpsApi Script example: Use-AzureDevOpsApi -Pat $Pat .LINK System access token: https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken .NOTES Author : Sjoerd Hooft Version: 2022-08-03 #> [CmdletBinding()] param ( [Parameter()] [ValidateLength(52,52)] # See for more parameter validation https://poshcode.gitbook.io/powershell-practice-and-style/style-guide/function-structure [ValidateSet("dev", "tst", "acc")] [string] $Pat ) begin { Write-Host "##[section]Function: $($MyInvocation.MyCommand)" Write-Verbose "Input: $($PSBoundParameters | Out-String)" # Set Verbose switch based on PSBoundParameters $CmdLetOutput = @{Verbose = $($PSBoundParameters.Verbose)} # Collect information } process { # Do stuff } end { # Cleanup } }
PowerShell Function Validates
- Not null or empty:
[ValidateNotNullOrEmpty()]
- Latest or YYYY-MM:
[ValidatePattern("latest|20\d{2}[-]\d{2}")]
- Email:
[ValidatePattern('(.+@getshifting\.com)$')]
- Specific server name:
[ValidatePattern("web(dev|tst|acc)dmz0[12]")]
- Environment:
[ValidateSet("dev", "tst", "acc", "prd")]
- Number between:
[ValidateRange(8,100)]
- Length range:
[ValidateLength(8,12)]
- Length exactly:
[ValidateLength(8,8)]
PowerShell Modules
Check Azure powershell module depending on PS version
Write-Host "Check required PowerShell Modules `n" # The "new" PS module for Azure requires PowerShell 7 if ($($PSVersionTable.PSVersion).Major -eq 7){ if (Get-Module -ListAvailable -Name AZ) { Write-Host "PowerShell module Azure exists" } else { Write-Host "PowerShell module Azure does not exist. Start installation. " Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force } }else{ Throw "Powershell needs to be version 7" }
PowerShell DNS Moduleif (Get-Module -ListAvailable -Name DnsServer) { Write-Host "PowerShell module DnsServer exists" } else { Write-Host "Module DNSServer does not exist. Starting installation" Import-Module ServerManager Add-WindowsFeature -Name "RSAT-DNS-Server" }
PowerShell AD Module# Because ActiveDirectory is a 5.1 module you need to add -All if (Get-Module -ListAvailable -All -Name ActiveDirectory) { Write-Host "PowerShell module ActiveDirectory exists" } else { Write-Host "Module ActiveDirectory does not exist. Starting installation" Import-Module ServerManager Add-WindowsFeature -Name "RSAT-AD-PowerShell" –IncludeAllSubFeature }
PowerShell Pester module, remove shipped version and install latest version (Needs PS 7)
if (Get-Module -ListAvailable -Name Pester) { # Check for version 3.4 and if available remove it Get-Module -ListAvailable -Name Pester if (((((Get-Module -ListAvailable -Name Pester).Version).Major) -eq 3) -AND ((((Get-Module -ListAvailable -Name Pester).Version).Minor) -eq 4)) { Write-Host "PowerShell Module Pester is version 3.4 which is shipped along with Win10/Windows 2016. Start removal:" $module = "C:\Program Files\WindowsPowerShell\Modules\Pester" takeown /F $module /A /R icacls $module /reset icacls $module /grant "*S-1-5-32-544:F" /inheritance:d /T Remove-Item -Path $module -Recurse -Force -Confirm:$false } # Verifieer of Pester al aanwezig met minimaal versie 5 if ((((Get-Module -ListAvailable -Name Pester).Version).Major) -ne 5) { Write-Host "PowerShell module Pester is not up to date" Install-Module -Name Pester -Force -Scope CurrentUser }else{ Write-Host "PowerShell Module Pester is available with minimal version of 5:" Get-Module -ListAvailable -Name Pester } } else { Write-Host "PowerShell module Pester does not exist. Start installation. " Install-Module -Name Pester -Force -Scope CurrentUser }
IIS Administration Module, install extra version, see the version and the available commandlets. Note that this needs to be done in PowerShell 5 Administrative ShellInstall-Module -Name IISAdministration -Scope AllUsers -Force #Installs latest version next to it (1.1.0.0) Import-Module IISAdministration -RequiredVersion 1.1.0.0 $mod = Get-Module -Name IISAdministration $mod.Version $mod.ExportedCmdlets | Format-Table
Import PS ModuleImport-Module Pester
Get commands within a moduleGet-Command -module Pester
Get module for a commandGet-Command Get-Service
Remove / Unload a PowerShell moduleRemove-Module Pester
PowerShell Requires
#Requires -Version 7.0 #Requires -PSEdition Core # Requires for modules is slow because it also imports them # Requires does not work for non-PS Core modules like DNS and ActiveDirectory #Requires -Modules @{ ModuleName="Pester"; ModuleVersion="5.0" } #Requires -Modules Az #Requires -Modules AzureRmStorageTable
PowerShell ForEach
With custom PS Object and export to csv
$myCol = @() foreach ($vm in (get-vmhost esxprd101.intranet | get-vm )){ $VMInfo = "" | Select-Object VMName,VMHostName,NICCount $VMInfo.VMName = $vmview.Name $VMInfo.VMHostName = $vmview.Guest.HostName $VMInfo.NICCount = $vmview.Guest.Net.Count $myCol += $VMInfo } $myCol |Export-csv -NoTypeInformation $csvfile
PowerShell Comparison
Overview# logical and comparison # -and, -or, -not , ! : Connect expressions # -eq, -ne : Equal, not equal # -gt / -lt, -ge / -le : Greater/less than, greater or equal / less or equal # -replace # -match / -notmatch : Regular expression match # -like / -notlike : wilcard matching # -contains / -notcontains : check for value in array: $array -contains $value # -in / -notin : reverse syntax from contains: $value in $array
PowerShell Location
Change directory (alias cd)Set-Location c:\
Change directory and backPS C:\Users\sjoer> Push-Location c:\ PS C:\> Pop-Location PS C:\Users\sjoer>
Azure PowerShell
NOTE: Module AZ only works in PowerShell 7
TLS version# Set TLS version to use TLS 1.2 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Login to Azure
Login and contextConnect-AzAccount Get-AzContext -ListAvailable Set-AzContext -Name $dtapEnvironment -Subscription $azureSubscriptionName
Get TenantId$tenantId = (Get-AzContext).Tenant.Id
KeyVault
Get secret from KeyVault$adadminpass = (Get-AzKeyVaultSecret -VaultName kv-operations-global -Name "adAdminPass").SecretValue
Set secret to KeyVault$userpasswordsecure = ConvertTo-SecureString -String $userpassword -AsPlainText -Force Set-AzKeyVaultSecret -VaultName kv-operations-global -Name $username -SecretValue $userpasswordsecure
Resourcegroup Creation Time
((Invoke-AzRestMethod -Path "/subscriptions/$subId/resourcegroups?api-version=2020-06-01&`$expand=createdTime" -Method GET).Content | ConvertFrom-Json).value | Select-Object name,createdTime
cheatsheet-powershell.txt · Last modified: by 127.0.0.1