DS DevShelfHub Projects · AI tools
Cheatsheets / PowerShell
Cheatsheet · Languages

PowerShell 7 Cheatsheet: Cmdlets, Pipelines, Objects and Modules

By DevShelfHub

Cmdlets, pipelines, objects, parameters, arrays, hashtables, comparison/logic operators, scripts, modules, remoting — the PowerShell 7 surface.

118 items 8 min Cmdlets Objects Pipelines

Start hereQuick start · 6 you’ll reach for daily

FilterWhere-Object { $_.X —gt 0 }
MapForEach-Object { $_.Name }
ProjectSelect-Object Name, Id
GroupGroup-Object Status
Parallel%-Parallel -ThrottleLimit 4
JSONConvertTo-Json / -FromJson

Target versions · paceVersions

Targets: PowerShell 7.x (cross-platform) Windows PowerShell 5.1 (Windows-only legacy) .NET 8 runtime

Use PowerShell 7 (pwsh) for new work — it runs on macOS, Linux, and Windows, and ships ForEach-Object -Parallel, ?? / ?. operators, ternary a ? b : c, and pipeline chains (&& / ||). Windows PowerShell 5.1 is the in-box Windows version — still supported, no new features. Modules: PSReadLine (interactive UX), Pester (tests), PSScriptAnalyzer (lint).

Install · profileSetup

powershell
# Install PowerShell 7 (cross-platform)
brew install --cask powershell                   # macOS
winget install --id Microsoft.PowerShell         # Windows
sudo apt install -y powershell                   # Debian/Ubuntu (via packages.microsoft.com)

# Versions
pwsh -v                                          # PowerShell 7.x (cross-platform "Core")
powershell -v                                    # Windows PowerShell 5.1 (Windows only, legacy)

# Profile (per-host)
notepad $PROFILE                                 # opens $HOME/.config/PowerShell/Microsoft.PowerShell_profile.ps1
. $PROFILE                                       # reload without restarting

# Run a script
pwsh ./build.ps1
pwsh -File ./build.ps1 -ConfigPath ./prod.json

# Daily commands
Get-Help Get-ChildItem -Examples                 # docs + examples
Get-Command -Module Az                           # list cmdlets in a module
Update-Help                                      # refresh help locally

Verb-Noun conventionCmdlets

Every command is a verb-noun pair. Approved verbs are stable; nouns are singular. Aliases (ls, cat, cd) exist for muscle memory — never use them in scripts.

Get-ChildItem [-Path] [-Recurse] [-File] [-Filter]List files / directories. Alias: ls, dir.
Get-Content pathRead a file. Streams lines. Alias: cat.
Set-Content path -Value … / Add-ContentWrite / append.
Set-Location / Push-Location / Pop-Locationcd / cd-stack push / pop.
Get-Process / Stop-Process / Start-ProcessProcess control.
Get-Service / Restart-ServiceService management (Windows + systemd via PSCore).
Get-Command verb-* / Get-Command -Module AzDiscover cmdlets.
Get-Help cmdlet -Examples / -Detailed / -OnlineIn-shell docs.
Get-MemberList properties + methods on whatever’s piped in. Indispensable.
$PSVersionTable / $PROFILE / $env:NAMECommon automatic variables.

$ prefix · typedVariables & types

$name = "Ada"Loose typing. Sigils are required.
[int]$age = 36Typed declaration. Coerces or throws.
Set-Variable -Name x -Value 5 -Option ReadOnlyConstant-style variable.
$null / $true / $falseNull + booleans.
$env:HOME / $env:PATHEnvironment variables.
$_Current pipeline object (also $PSItem).
$args / $PSBoundParametersFunction args (legacy) / named arg dict.
[string], [int], [datetime], [hashtable], [array]Common type literals.
[pscustomobject]@{ Name = 'Ada'; Age = 36 }Preferred Quick anonymous object.
[System.IO.Path]::Combine($a, $b)Call any .NET static method.
New-Object -TypeName System.Uri -ArgumentList "…"Construct a .NET object (verbose form).
[Uri]::new("…")Modern constructor syntax.

Everything is an objectPipeline & objects

cmd1 | cmd2 | cmd3Pipe objects, not text. Big difference from Bash.
Where-Object { $_.X -gt 0 } / ? { … }Filter. ? is the alias.
ForEach-Object { … } / % { … }Map / iterate. % is the alias.
ForEach-Object -Parallel { … } -ThrottleLimit 4PS7+ parallel map. Runs in a runspace pool.
Select-Object Name, IdProject to a subset of properties.
Select-Object -First 10 / -Last 10 / -UniqueSlicing helpers.
Select-Object @{ n='MB'; e={ $_.Size / 1MB } }Calculated property — name + expression.
Sort-Object Name, Age -DescendingMulti-key sort.
Group-Object StatusSQL-style GROUP BY. Returns Name + Count + Group.
Measure-Object Length -Sum -AverageAggregate stats over a numeric property.
Format-Table -AutoSize / Format-ListDisplay. Last stage only — downstream cmdlets can’t consume formatted output.
Out-File / Out-Host / Out-NullSend to file, console, void.
Tee-ObjectSplit the pipeline: file + downstream.

Worked example

powershell
# Everything in the pipeline is an OBJECT — not text.
# That's the single difference that explains all the rest.

# Get the 5 biggest files in the current tree
Get-ChildItem -Recurse -File `
  | Sort-Object Length -Descending `
  | Select-Object -First 5 -Property FullName, Length

# Filter + project + group + summarize
Get-Process `
  | Where-Object   { $_.WS -gt 100MB } `
  | Select-Object  Name, @{ n='WS_MB'; e={ [math]::Round($_.WS/1MB, 1) } } `
  | Sort-Object    WS_MB -Descending `
  | Format-Table   -AutoSize

# Group then aggregate (like SQL GROUP BY)
Get-ChildItem -Recurse -File `
  | Group-Object   Extension `
  | Sort-Object    Count -Descending `
  | Select-Object  -First 5 Name, Count, `
                   @{ n='SizeMB'; e={ [math]::Round(($_.Group | Measure-Object Length -Sum).Sum / 1MB, 1) } }

# Export anywhere
Get-Process | Select-Object Name, Id, WS | Export-Csv ./procs.csv -NoTypeInformation
Get-Process | ConvertTo-Json | Out-File ./procs.json

Comparison · logic · arithmeticOperators

-eq / -ne / -lt / -le / -gt / -geEquality + comparison. Case-insensitive on strings by default.
-ceq / -cne / -clt / …Case-sensitive variants.
-like / -notlikeGlob match: *, ?.
-match / -notmatchRegex match. Sets $Matches.
-replaceRegex replace.
-contains / -notcontainsMembership test on collection. $arr -contains 5.
-in / -notinReverse operands: 5 -in $arr.
-and / -or / -not / -xorBoolean logic. Not && for boolean expressions.
&& / ||Pipeline chain (PS7+). Run next only on success / failure.
??, ??=Null-coalesce + assign-if-null (PS7+).
$obj?.Prop?.Method()Null-conditional member access (PS7+).
a ? b : cTernary (PS7+).
+ - * / % (string + array support overloads)Arithmetic. "hi" * 3 = repeat. @(1,2) + @(3) = concat.

Interpolation · here-stringsStrings

"hi $name"Double-quoted interpolation.
"hi $($obj.Name)"$() for arbitrary expressions.
'no interp'Single-quoted literal.
@"\n…\n"@Here-string with interpolation. Multi-line.
@'\n…\n'@Literal here-string.
"x = {0,5}" -f $valueFormat operator. .NET format strings.
[string]::Format("{0:N2}", $pi)Direct .NET formatting.
$s.Substring(0, 10) / Split('.') / Trim()Standard .NET String methods.
$s -split ',' / -join ','Split returns array; join collapses.
$s -replace 'old', 'new'Regex replace.
"line1`nline2`tcol"Escapes use backtick: `n, `t, `r, `".

CollectionsArrays & hashtables

Arrays

$xs = 1, 2, 3 / @(1, 2, 3)Comma builds an array. @() forces array semantics — even on a single result.
$xs[0] / $xs[-1] / $xs[0..2]Index, last, slice.
$xs.Length / .CountLength.
$xs += 4Append. Creates a new array — O(n).
$list = [System.Collections.Generic.List[int]]::new(); $list.Add(1)Preferred Real growable list for hot loops.
$xs -join ',' / 'a,b' -split ','String ⇆ array.
@() / ,1Empty array / single-element array (without unwrapping).

Hashtables / ordered dictionaries

$h = @{ Name = 'Ada'; Age = 36 }Hashtable. Case-insensitive keys.
$h['Name'] / $h.NameTwo equivalent accesses.
$h.Keys / $h.ValuesIterate.
$h.Add('Email', 'a@b') / $h.Remove('Age')Mutate.
[ordered]@{ … }Preserves insertion order. Use when serializing.
$h.ContainsKey('Name')Existence test.
Get-Help cmdlet @paramsSplatting — expand a hashtable into named args.

if · switch · loopsControl flow

if ($x -gt 0) { … } elseif … else { … }Standard. Parens required.
switch ($x) { 1 { … } 2 { … } default { … } }Falls through unless break.
switch -Regex / -Wildcard / -CaseSensitive ($x)Match modes.
switch -File "log.txt" { 'ERROR' { … } }Stream a file line-by-line.
for ($i = 0; $i -lt 10; $i++) { … }C-style.
foreach ($x in $xs) { … }Statement, not the cmdlet. Faster than ForEach-Object for in-memory arrays.
while / do { … } while / do { … } untilStandard.
break / continue / returnLoop / function control flow.

Params · pipeline inputFunctions

function Get-Foo { param([string]$Name) … }Define + typed param.
[CmdletBinding()]Promote to advanced function. Unlocks -Verbose / -WhatIf / -ErrorAction.
[Parameter(Mandatory)] [string]$NameRequired parameter.
[Parameter(ValueFromPipeline)]Accept pipeline input. Pair with process { … }.
[ValidateSet('A','B','C')] / [ValidateRange(1,100)] / [ValidateScript({ … })]Attribute validation.
begin { } process { } end { }Pipeline lifecycle blocks. process runs per item.
[switch]$ForceBoolean flag.
$PSCmdlet.WriteVerbose("…")Verbose stream. Visible with -Verbose.
[OutputType([System.IO.FileInfo])]Declare output type. Helps IntelliSense.
Splatting: Get-Foo @paramsPass a hashtable of args. Best for many params.

Worked example

powershell
# Advanced function with typed parameters, pipeline input, and validation

function Get-LargeFile {
    [CmdletBinding()]
    [OutputType([System.IO.FileInfo])]
    param(
        [Parameter(Mandatory, Position = 0, ValueFromPipeline)]
        [ValidateScript({ Test-Path $_ })]
        [string] $Path,

        [ValidateRange(1, [int]::MaxValue)]
        [int] $MinSizeMB = 10,

        [switch] $Recurse
    )

    process {
        $bytes = $MinSizeMB * 1MB
        Get-ChildItem -Path $Path -File -Recurse:$Recurse `
          | Where-Object { $_.Length -ge $bytes }
    }
}

# Call it
Get-LargeFile -Path . -MinSizeMB 50 -Recurse

# Pipeline-style
"." | Get-LargeFile -MinSizeMB 25 -Recurse

# Splatting — pass a hashtable of args
$params = @{
    Path        = '.'
    MinSizeMB   = 100
    Recurse     = $true
}
Get-LargeFile @params

try · trap · streamsErrors

try { … } catch [System.IO.IOException] { … } finally { … }Typed catch. Most-specific first.
$_ / $PSItemInside catch, the ErrorRecord.
throw "msg" / throw [System.ArgumentException]::new('…')Throw a terminating error.
$ErrorActionPreference = 'Stop'Globally promote non-terminating → terminating. Common in scripts.
Get-Foo -ErrorAction Stop / -ErrorAction SilentlyContinuePer-call override.
$Error[0]Most recent error. $Error.Clear() resets.
trap { …; continue }Script-wide handler. Like Bash trap.
Write-Error / Write-Warning / Write-Verbose / Write-Information / Write-DebugDifferent streams. Each has its own preference variable.
2>&1 / *>&1Redirect specific stream (2 = error) or all into stdout.

Files · HTTP · packagesI/O & modules

Get-Content -Raw / -TotalCount 100Whole file as string / first N lines.
Out-File -Encoding utf8 / -NoNewlineWrite. Specify encoding explicitly.
Import-Csv data.csv / Export-Csv -NoTypeInformationCSV ⇆ objects.
ConvertTo-Json -Depth 5 / ConvertFrom-JsonJSON. Default depth is shallow — bump for nested data.
Invoke-RestMethod -Uri … -Headers @{} -Body $objPreferred Returns parsed object. JSON auto-detected.
Invoke-WebRequestRaw HTTP response (headers, status, content).
Install-Module <Name> -Scope CurrentUserFrom PSGallery.
Import-Module <Name>Load. PS7 auto-imports on first call.
Get-Module -ListAvailableInstalled modules.
New-Item / Remove-Item / Copy-Item / Move-Item / Rename-ItemFileSystem cmdlets. Same shape for registry / certs.
Test-Path / Resolve-PathExistence test / canonicalize.

Concurrent REST · ~40 linesEnd-to-end · Parallel HTTP

Fan out GitHub API calls with ForEach-Object -Parallel, build typed objects, group + aggregate, persist to JSON. Same shape as a SQL pipeline but every stage is a cmdlet.

powershell
# Concurrent REST calls + parsed objects + grouped output
# Requires PowerShell 7+ (ForEach-Object -Parallel)

$owners = 'PowerShell', 'microsoft', 'github'

$results = $owners | ForEach-Object -Parallel {
    $owner = $_
    try {
        $repos = Invoke-RestMethod `
            -Uri "https://api.github.com/users/$owner/repos?per_page=5" `
            -Headers @{ 'User-Agent' = 'devshelf' } `
            -TimeoutSec 5

        $repos | Select-Object `
            @{ n = 'Owner';  e = { $owner } }, `
            @{ n = 'Name';   e = { $_.name } }, `
            @{ n = 'Stars';  e = { $_.stargazers_count } }, `
            @{ n = 'Lang';   e = { $_.language } }
    }
    catch {
        Write-Warning "$owner failed: $($_.Exception.Message)"
    }
} -ThrottleLimit 4

# Group + summarize
$results `
  | Group-Object Owner `
  | ForEach-Object {
        $totalStars = ($_.Group | Measure-Object Stars -Sum).Sum
        [pscustomobject]@{ Owner = $_.Name; Repos = $_.Count; TotalStars = $totalStars }
    } `
  | Sort-Object TotalStars -Descending `
  | Format-Table -AutoSize

# Persist to JSON
$results | ConvertTo-Json -Depth 4 | Out-File ./repos.json

Best practiceGood to know

Use Get-Member when stuck. Pipe anything into Get-Member and you see every property and method available. It’s how you discover the shape of an opaque cmdlet’s output without reading docs.
Never use aliases in scripts. ls, %, ? are great interactively but obscure intent. PSScriptAnalyzer flags them — treat that as a hard error in CI.
foreach statement is faster than the cmdlet for in-memory data. ForEach-Object processes one item per pipeline step; foreach (..) iterates a materialized array. Reach for the statement when you already have the array.

Common trapsWatch out for

Single-result cmdlets unwrap arrays. $x = Get-ChildItem | Where-Object … can give you a single object OR an array. Wrap with @() when you expect a collection.
Format-* kills downstream cmdlets. Get-Process | Format-Table | Export-Csv exports formatting metadata, not the objects. Keep Format-* at the very end.
Comparison operators are case-insensitive by default. 'A' -eq 'a' is true. Use the -c prefix (-ceq, -cmatch) when case matters — especially when comparing hashes or tokens.

Go deeperSee also

PowerShell FAQ

What is PowerShell 7?

PowerShell 7 is the open-source, cross-platform successor to Windows PowerShell 5.1. It runs on Windows, macOS, and Linux, ships with a modernised standard library, supports parallel pipelines with ForEach-Object -Parallel, and adds null-coalescing operators and pipeline chain operators. PowerShell 7 is the recommended version for all new scripting and automation work.

What are cmdlets in PowerShell?

Cmdlets (pronounced command-lets) are compiled .NET commands that follow a Verb-Noun naming convention such as Get-Process, Set-Item, or Remove-Item. Each cmdlet accepts named parameters and outputs .NET objects rather than plain text, making it easy to pipe structured data between commands. Use Get-Command -Verb Get to list all cmdlets with a given verb.

How does the PowerShell pipeline work?

The PowerShell pipeline passes .NET objects between cmdlets, not text strings. Get-Process | Where-Object CPU -gt 10 | Sort-Object CPU -Descending pipes process objects, filters by CPU usage, and sorts — all without any string parsing. Use Select-Object to pick properties and Export-Csv or ConvertTo-Json to serialise the final objects to a file or string.

How do hashtables work in PowerShell?

A hashtable is a key-value collection defined with @{key = value}. Access values with $ht['key'] or $ht.key. Hashtables are commonly used as named parameter splats (@params instead of individual -Param arguments) and to build custom objects with [PSCustomObject]@{Name='x'; Value=1}. Use [ordered]@{} to preserve insertion order in PowerShell 3+.

How do I handle errors in PowerShell?

Set $ErrorActionPreference = 'Stop' to make all errors terminating, then wrap code in try/catch/finally blocks. The catch block receives the exception in $_ or $PSItem; access the original error record via $_.Exception. Use -ErrorAction Stop on individual cmdlets to override the preference just for that call. Write-Error emits a non-terminating error; throw generates a terminating one.