PowerShell — Cheat Sheet

Tags: powershell, scripting, automation, windows, cli, devops, sysadmin

Level: intermediate

TL;DR: PowerShell is an object-oriented shell and scripting language built on .NET. It passes structured objects through pipelines rather than raw text streams.

Key concepts

Everything in the pipeline is a .NET object, preserving properties and methods across commands.

Cmdlet naming follows a strict Verb-Noun pattern such as Get-Process or Set-Item.

Modules bundle cmdlets, providers, functions, and variables for modular reuse.

Providers expose diverse data stores, such as the registry or certs, like standard filesystem drives.

The pipeline uses streaming execution: downstream commands process objects as upstream yields them.

Execution policies are safety controls to prevent accidental execution, not security boundaries.

Common parameters like -ErrorAction, -WhatIf, and -Confirm are built into advanced functions.

Output streams are numbered: 1 is Success, 2 Error, 3 Warning, 4 Verbose, 5 Debug, 6 Information.

PowerShell 7+ is cross-platform and runs on .NET Core across Windows, Linux, and macOS.

Remoting uses WinRM on Windows and OpenSSH cross-platform via Invoke-Command and Enter-PSSession.

Typical questions and ready answers

Q: How does the PowerShell pipeline differ from a traditional Unix pipeline?R: Unix pipelines pass streams of untyped byte/text data that require parsing with tools like awk or sed. PowerShell passes typed .NET objects, allowing direct access to strongly-typed properties and methods downstream.

Q: What is the difference between $_ and $PSItem?R: They are identical; $PSItem is simply the explicit, readable alias for $_, representing the current object in the pipeline.

Q: What is the difference between terminating and non-terminating errors?R: Non-terminating errors write to stream 2 and continue execution, while terminating errors halt execution. I control non-terminating error behavior using -ErrorAction Stop to convert them into catchable terminating exceptions.

Q: Why should you avoid Write-Host in reusable automation scripts?R: Write-Host writes directly to the console host rather than the pipeline output stream (prior to PS 5.0, where it was tied to stream 6). I use Write-Output for returning pipeline data or Write-Verbose for operational logging.

Q: How do you execute commands concurrently across remote machines?R: I use Invoke-Command -ComputerName ... -ScriptBlock { ... }, which runs the block across targets in parallel over WinRM, or background jobs with Start-ThreadJob for local concurrency.

Pitfalls and common mistakes

Array appending with += creates a brand new array copy every iteration, causing O(N^2) performance degradation on large collections.

FilterScript inside Where-Object inspects every single object; filter as far left as possible using cmdlet-native parameters like -Filter.

return in PowerShell does not discard uncaptured pipeline output produced earlier in the function.

Backtick (```) line continuation is fragile because trailing whitespace after it breaks parsing.

String comparison with -eq on an array acts as a filter returning matches rather than returning a single boolean.

Not using [CmdletBinding()] prevents scripts from inheriting common parameters like -Verbose or standard error controls.

Snippets and commands

# Discover commands, parameters, and documentation
Get-Command -Verb Get -Noun *Service*
Get-Help Get-Process -Examples
Get-Process | Get-Member -MemberType Property

# Efficient filtering and projection
Get-Service | Where-Object { $_.Status -eq 'Running' } | Select-Object -Property Name, DisplayName, StartType

# Pipeline-safe collection processing (avoiding += overhead)
$result = [System.Collections.Generic.List[string]]::new()
Get-ChildItem -Path ./src -Filter *.cs -Recurse | ForEach-Object {
    $result.Add($_.FullName)
}

# Advanced function template with CmdletBinding
function Invoke-SafeDeploy {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Environment,

        [ValidateSet('Rolling', 'BlueGreen')]
        [string]$Strategy = 'Rolling'
    )

    process {
        if ($PSCmdlet.ShouldProcess($Environment, "Deploying with $Strategy strategy")) {
            Write-Verbose "Starting deployment to $Environment..."
            # Core logic
        }
    }
}

# Error handling with terminating conversion
try {
    Stop-Service -Name "NonExistentService" -ErrorAction Stop
} catch [System.ServiceProcess.ServiceCommandException] {
    Write-Warning "Service operation failed: $($_.Exception.Message)"
} catch {
    Write-Error "Unexpected failure: $($_.Exception.Message)"
} finally {
    Write-Verbose "Cleanup executed."
}

# Remote execution across multiple nodes
Invoke-Command -ComputerName 'srv-web-01', 'srv-web-02' -ScriptBlock {
    Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -Name Release
}

To review

[ ] Implement custom parameter completers with Register-ArgumentCompleter

[ ] Measure performance differences between ForEach-Object and the language statement foreach ($x in $coll)

[ ] Validate custom module manifests (.psd1) using Test-ModuleManifest

[x] Manage terminating vs non-terminating exceptions with $ErrorActionPreference

[x] Extract object properties using Select-Object -ExpandProperty

[x] Configure remote sessions using OpenSSH transport in PowerShell 7

References

Microsoft Learn PowerShell Documentation: [learn.microsoft.com/powershell](https://learn.microsoft.com/powershell)

PowerShell GitHub Repository: [github.com/PowerShell/PowerShell](https://github.com/PowerShell/PowerShell)

Jarvis Interviews
Jarvis