# PowerShell cheat sheet: language & syntax

> PowerShell language cheat sheet: types, comparison operators, pipelines, quotes, here-strings, arrays, hashtables, splatting and aliases.

- Page URL: https://itinsighthub.com/powershell/language/
- Markdown variant of this page: append `?format=md` to any URL on this site or send `Accept: text/markdown`.
- Full site index for AI assistants: https://itinsighthub.com/llms.txt
- Full site export: https://itinsighthub.com/llms-full.txt

# 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`.

Published August 22, 2026

## The building blocks

*Data types you will actually type. All of them behave the same in 5.1 and 7.*

| Type | Created with | Gotcha |
| --- | --- | --- |
| string | 'single' or "double" quotes | double quotes expand variables; single quotes are literal |
| int / decimal | 42, 1.5, 0x2A | division always returns a double: 5 / 2 is 2.5, not 2 |
| bool | $true, $false | comparisons resolve to bool; -and binds tighter than -or |
| array | @(1,2,3) or 1,2,3 | a 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.*

| Alias | Cmdlet | Note |
| --- | --- | --- |
| gci, ls | Get-ChildItem | ls works in cmd and PowerShell but means different things |
| gp | Get-ItemProperty | registry values — not a PSDrive listing |
| gm | Get-Member | the object inspector: pipe anything into gm |
| sls | Select-String | grep-style search inside files |
| sc | Set-Content | NOT sc.exe — that is Service Control (a different tool entirely) |
| ps, gps | Get-Process | command name shadows the process list itself |
| iex | Invoke-Expression | executes a string — only run strings you trust |
| ?, % | Where-Object, ForEach-Object | short forms of piping workhorses |

Help and discovery commands

- **Get-Help :** local help; add -Examples and -Detailed for more depth
- **Get-Help  -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.

## References

- [PowerShell 101](https://learn.microsoft.com/en-us/powershell/scripting/learn/ps101/00-introduction) — Microsoft's structured tutorial series covering every concept on this sheet.
- [about_Pipelines](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pipelines) — object pipeline semantics explained officially.

## 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' }.

## Related tools

- [IPv4 subnet calculator](https://itinsighthub.com/subnet-calculator/) — break any CIDR block into network, range, broadcast and usable hosts.
- [IP range to CIDR](https://itinsighthub.com/ip-range-to-cidr/) — turn an arbitrary address range into its minimal covering CIDR blocks.
- [VLSM calculator](https://itinsighthub.com/vlsm-calculator/) — split a block into right-sized subnets by host requirements.

---

© 2026 ITInsightHub · [About](https://itinsighthub.com/about/) · [Contact](https://itinsighthub.com/contact/) · [Privacy](https://itinsighthub.com/privacy/)
