PowerShell cheat sheet: language & syntax

This sheet is the grammar layer: the pieces you need before any real script. It targets the two runtimes you actually have — Windows PowerShell 5.1 (powershell.exe) and PowerShell 7 (pwsh) — and everything below behaves identically in both unless noted.

Two ideas run through all of it. First, PowerShell touches objects: every command emits .NET objects, and the pipeline passes objects, not text (this is the single biggest difference from cmd). Second, syntax is verb-noun and parameter-flag: Get-Service -Name BITS reads as an action against a thing, and parameters are -Flag Value — never cmd's /flag value.

The building blocks

Data types you will actually type. All of them behave the same in 5.1 and 7.
TypeCreated withGotcha
string'single' or "double" quotesdouble quotes expand variables; single quotes are literal
int / decimal42, 1.5, 0x2Adivision always returns a double: 5 / 2 is 2.5, not 2
bool$true, $falsecomparisons resolve to bool; -and binds tighter than -or
array@(1,2,3) or 1,2,3a single-item array needs @( ); an object unrolls down the pipeline
hashtable@{ Name = 'BITS' }key values use = ; separate entries with ; or line breaks
pscustomobject[pscustomobject]@{ Name = 'BITS' }the shaped object form of a hashtable — good for CSV export

Operators: comparison, matching and logic

-eq / -ne
equals / not-equals. Case-insensitive by default; -ceq / -cne for exact case
-lt / -gt / -le / -ge
less than, greater than, and their inclusive forms — numbers, dates and strings
-like / -notlike
wildcard match: * any run, ? single char. Case-insensitive
-match / -notmatch
regular expression match; $Matches receives the groups
-contains / -in
array membership: 2 -in @(1,2,3); -notcontains for the negative
-and / -or / -not
logical tests; use parentheses to control grouping
-replace
regex replace: "a-b" -replace "-", "+"
-is / -isnot
type test: $_.Size -is [int]

Pipelines: objects, not text

The canonical example — filter, then pick columns
Get-Service | Where-Object Status -eq "Running" | Select-Object Name, Status
$_ and the two idioms that use it
# Scriptblock form — $_ is the current object in the pipeline
Get-Process | Where-Object { $_.ProcessName -like "*sql*" }

# Simplified form — property, comparison operator, value
Get-Process | Where-Object ProcessName -like "*sql*"

# ForEach-Object transforms each item
1..10 | ForEach-Object { $_ * $_ }

# Aliases: ? is Where-Object, % is ForEach-Object, gm is Get-Member
Get-Service | ? Status -eq "Running" | % Name | gm
$_ (also available as $PSItem) is the automatic variable that holds the current object in the pipeline. It only exists inside script blocks passed to Where-Object, ForEach-Object and friends. The simplified filter syntax — Where-Object Status -eq "Running" — is PowerShell 3+ and works identically in 5.1 and 7.

Quotes and here-strings

The four string forms, in order of how often you will type them

'single quotes'
literal text — variables are NOT expanded. Default for fixed strings
"double quotes"
string expansion: $name and $(command) are evaluated
@'...'@ here-string
multi-line literal block; closing @' must be at the start of a line
@"..."@ here-string
multi-line expanded block; use when a text block contains both $ and line breaks
` (backtick)
escape character inside strings: `" quotes the quote, `$ quotes the dollar sign

Arrays, hashtables and splatting

The three @-containers and the most underused one: splatting
# Array — comma syntax, or @() for explicit arrays
$servers = @("srv01", "srv02", "srv03")

# Hashtable — note the = between key and value
$config = @{
  Name   = "BITS"
  State  = "Running"
  Secure = $true
}

# Splatting — @ in front of a variable whose value is a hashtable
$params = @{ Name = "BITS"; StartupType = "Automatic" }
Set-Service @params

# Shaped object — hashtable cast to an object with real properties
$result = [pscustomobject]@{ Server = "srv01"; FreeGB = 42.5 }
Splatting is @params, not $params — the @ marks the hashtable as a parameter bag. Without it, Get-Service $params tries to pass the whole hashtable as the name. Arrays and hashtables are also why Get-Service | Where-Object Status -eq "Running" can sit in one line while a full script grows a line per role: add data, then filter, then select.

Aliases and getting help

Built-in aliases, present in both 5.1 and 7 — every mapping here is the documented one.
AliasCmdletNote
gci, lsGet-ChildItemls works in cmd and PowerShell but means different things
gpGet-ItemPropertyregistry values — not a PSDrive listing
gmGet-Memberthe object inspector: pipe anything into gm
slsSelect-Stringgrep-style search inside files
scSet-ContentNOT sc.exe — that is Service Control (a different tool entirely)
ps, gpsGet-Processcommand name shadows the process list itself
iexInvoke-Expressionexecutes a string — only run strings you trust
?, %Where-Object, ForEach-Objectshort forms of piping workhorses

Help and discovery commands

Get-Help <cmdlet>
local help; add -Examples and -Detailed for more depth
Get-Help <cmdlet> -Online
opens the Microsoft Learn reference page in a browser
Get-Command -Verb Get
lists every cmdlet whose verb is, say, Get
Get-Command -Noun Service
lists cmdlets operating on a noun — Get-Service, Set-Service, New-Service
Update-Help
downloads help files from the internet; needs elevation for system-wide modules

PowerShell 7 vs Windows PowerShell 5.1

PowerShell 7 (launched as pwsh) is a cross-platform rewrite on modern .NET: its 7.4 line runs on .NET 8, 7.5 on .NET 9, and the same shell works on Linux and macOS with different built-ins. Windows PowerShell 5.1 is the .NET Framework 4.x-era shell that ships in Windows 10/11, still the default console, and maintained but no longer the actively developed one. $PSVersionTable.PSVersion (or $PSVersionTable alone) always tells you which you are in. The rule that matters: core Microsoft.PowerShell.* cmdlets are compatible, but Windows-only modules are not — Get-CimInstance Win32_*, Get-NetAdapter, Get-NetIPAddress and friends simply do not exist in PowerShell 7 on Linux, because their providers ship in Windows. On Windows, both runtimes load them the same way. Get disk space with PowerShell and list installed software use only cross-compatible cmdlets and run in both.

FAQ

Is PowerShell 7 the same as Windows PowerShell?

No. Windows PowerShell 5.1 is the legacy, Windows-only shell that ships in Windows 10/11; PowerShell 7 (pwsh) is the modern cross-platform rewrite running on modern .NET and installs side by side with it. Common cmdlets work in both, but 5.1 cannot load PowerShell 7 modules and PowerShell 7 on Linux cannot load Windows-only modules like Get-NetAdapter or the Win32_* CIM classes. Check which one you are in with $PSVersionTable.

What does $_ mean?

$_ (or $PSItem) is the automatic variable holding the current object inside a pipeline script block. In Where-Object { $_.Status -eq 'Running' } the filter tests each incoming object through $_, and ForEach-Object { $_.Name } reads the same variable to transform each item. It exists only inside script blocks passed to pipelining cmdlets.

What is the difference between 'single quotes' and "double quotes"?

Double quotes expand the string: "$name" prints the value of the variable, and "$(Get-Date)" runs the expression. Single quotes are literal: '$name' prints the four characters $name. Multi-line needs here-strings — @'...'@ for literal, @"..."@ for expanded — and the closing marker must sit at the start of its own line.

What do @( ) and @{ } mean in PowerShell?

@( ) creates an array, @{ } creates a hashtable. The same @ token in front of a variable name — @params instead of $params — is splatting: it unpacks the hashtable into named parameters of a cmdlet, which is how you pass a reusable bind of options like $params = @{ Name='BITS'; StartupType='Automatic' }.