
If you've ever hit "unexpected token 'or'" in PowerShell and wondered why your perfectly reasonable if statement exploded, this is your cheat sheet. It covers the specific syntax gotchas that trip people up: why you need double parentheses around cmdlets in logical operators, why emoji will break your scripts, how to avoid null reference errors on arrays, and why ConvertTo-Json without a depth parameter will silently truncate your data. The quick reference tables are the real value here. Think of it as documentation for the parts of PowerShell that don't work the way you'd expect coming from other scripting languages.
$ npx -y skills add sickn33/antigravity-awesome-skills --skill powershell-windows --agent claude-codeInstalls into .claude/skills of the current project.
Critical patterns and pitfalls for Windows PowerShell.
| ❌ Wrong | ✅ Correct |
|---|---|
if (Test-Path "a" -or Test-Path "b") | if ((Test-Path "a") -or (Test-Path "b")) |
if (Get-Item $x -and $y -eq 5) | if ((Get-Item $x) -and ($y -eq 5)) |
Rule: Each cmdlet call MUST be in parentheses when using logical operators.
| Purpose | ❌ Don't Use | ✅ Use |
|---|---|---|
| Success | ✅ ✓ | [OK] [+] |
| Error | ❌ ✗ 🔴 | [!] [X] |
| Warning | ⚠️ 🟡 | [*] [WARN] |
| Info | ℹ️ 🔵 | [i] [INFO] |
| Progress | ⏳ | [...] |
PowerShell supports Unicode. ASCII log markers are a portability choice, not a syntax requirement. For non-ASCII scripts read by Windows PowerShell 5.1, use UTF-8 with BOM; PowerShell 7 uses UTF-8 without BOM by default. Check the consuming tool before choosing file encoding.
| ❌ Wrong | ✅ Correct |
|---|---|
$array.Count -gt 0 | ($null -ne $array) -and (@($array).Count -gt 0) |
$text.Length | if ($null -ne $text) { $text.Length } |
"Value: $($obj.prop.sub)" is valid subexpression interpolation. Store a complex expression in a variable when that improves readability.
Pattern:
$value = $obj.prop.sub
Write-Output "Value: $value"
| Value | Use |
|---|---|
| Stop | Required cmdlet failures must enter catch |
| Continue | Report a non-terminating error and continue deliberately |
| SilentlyContinue | When errors expected |
| Pattern | Use |
|---|---|
| Literal path | C:\Users\User\file.txt |
| Variable path | Join-Path $env:USERPROFILE "file.txt" |
| Relative | Join-Path $ScriptDir "data" |
Rule: Use Join-Path for cross-platform safety.
| Operation | Syntax |
|---|---|
| Empty array | $array = @() |
| Add item | $array += $item |
| ArrayList add | `$list.Add($item) |
| ❌ Wrong | ✅ Correct |
|---|---|
ConvertTo-Json | ConvertTo-Json -Depth 10 |
Rule: Always specify -Depth for nested objects.
| Operation | Pattern |
|---|---|
| Read | `Get-Content "file.json" -Raw |
| Write | `$data |
| Error Message | Cause | Fix |
|---|---|---|
| "parameter 'or'" | Missing parentheses | Wrap cmdlets in () |
| "Unexpected token" | Parsing or quoting error | Inspect the reported token and file encoding |
| "Cannot find property" | Null object | Check null first |
| "Cannot convert" | Type mismatch | Validate input and convert to the required type |
# Strict mode
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Paths
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
# Main
try {
# Cmdlet logic here; check $LASTEXITCODE after native executables.
Write-Output "[OK] Done"
exit 0
}
catch {
Write-Warning "Error: $_"
exit 1
}
Remember: Check shell version, encoding, null semantics and native exit codes.
try/catchalone does not reliably turn native command failures into exceptions.
References: encoding, quoting.
Use when writing or debugging Windows PowerShell or PowerShell 7 scripts, especially command expressions, encoding, paths and error handling.
Sponsors