Toolmingo
Guides12 min read

PowerShell Cheat Sheet: Commands, Scripting & Automation

A complete PowerShell cheat sheet covering cmdlets, pipelines, variables, loops, functions, error handling, file system, registry, remoting, and automation scripts.

The PowerShell reference for sysadmins and developers — cmdlets, pipeline tricks, scripting patterns, and real-world automation examples.

Quick reference

The 25 PowerShell patterns you use every week.

Task Command
List files Get-ChildItem / ls / dir
Filter output Where-Object { $_.Size -gt 1MB }
Select properties Select-Object Name, Length
Sort Sort-Object -Property LastWriteTime -Descending
Count items (Get-ChildItem).Count
Get help Get-Help Get-Process -Full
Run script .\script.ps1
Set execution policy Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Get all processes Get-Process
Kill process Stop-Process -Name notepad
Get services Get-Service
Start/stop service Start-Service wuauserv
Get environment var $env:PATH
Set env var $env:MY_VAR = "value"
Read file Get-Content file.txt
Write file `"text"
Copy item Copy-Item src.txt dst.txt
Move item Move-Item old.txt new.txt
Remove item Remove-Item file.txt
Test path Test-Path C:\folder
Measure string length "hello".Length
Format list `Get-Process
Format table `Get-Process
Export to CSV `Get-Process
Measure execution time Measure-Command { Get-ChildItem -Recurse }

Variables and data types

# Variables — prefix $
$name = "Alice"
$count = 42
$price = 9.99
$active = $true
$nothing = $null

# Type casting
[int]$x = "123"       # 123
[string]$s = 456      # "456"
[double]$d = "3.14"   # 3.14
[bool]$b = 1          # $true

# Type check
$name.GetType().Name   # String
$count -is [int]       # True

# Arrays
$colors = @("red", "green", "blue")
$colors[0]             # "red"
$colors[-1]            # "blue" (last)
$colors.Count          # 3
$colors += "yellow"    # append

# Array slicing
$colors[1..2]          # "green", "blue"

# Strongly typed array
[int[]]$nums = 1, 2, 3

# Hashtables (dictionaries)
$person = @{
    Name = "Bob"
    Age  = 30
    City = "Berlin"
}
$person.Name           # "Bob"
$person["Age"]         # 30
$person.Keys           # Name, Age, City
$person.ContainsKey("City")  # True
$person.Remove("City")

# Ordered hashtable
$ordered = [ordered]@{ a = 1; b = 2; c = 3 }

Strings

$s = "Hello, World!"

# Common string methods
$s.Length              # 13
$s.ToUpper()           # "HELLO, WORLD!"
$s.ToLower()           # "hello, world!"
$s.Trim()              # strip whitespace
$s.TrimStart("H")      # "ello, World!"
$s.Replace("World", "PowerShell")  # "Hello, PowerShell!"
$s.Split(", ")         # @("Hello", "World!")
$s.StartsWith("Hello") # True
$s.EndsWith("!")       # True
$s.Contains("World")   # True
$s.IndexOf("W")        # 7
$s.Substring(7, 5)     # "World"

# String interpolation (double quotes expand variables)
$user = "Alice"
"Hello, $user!"            # "Hello, Alice!"
"Count: $($arr.Count)"    # expression in $()

# Multiline here-string
$text = @"
Line one
Line two
Line three
"@

# Single-quoted — no expansion
'Hello, $user'             # "Hello, $user" (literal)

# String formatting
"Pi is {0:F2}" -f 3.14159  # "Pi is 3.14"
"{0,-10} {1,5}" -f "Name", "Score"  # left/right align

# Join strings
$words = "one", "two", "three"
$words -join ", "          # "one, two, three"

# Split
"a:b:c" -split ":"         # @("a", "b", "c")

# Regex match
"hello123" -match "\d+"    # True; $Matches[0] = "123"
"hello123" -replace "\d+", "XXX"  # "helloXXX"

Control flow

# If / elseif / else
if ($x -gt 10) {
    "big"
} elseif ($x -gt 5) {
    "medium"
} else {
    "small"
}

# Comparison operators
# -eq  -ne  -lt  -le  -gt  -ge
# -like (wildcards: * ?)
# -match (regex)
# -contains (array contains value)
# -in (value in array)
# Case-insensitive by default; prefix i for explicit: -ieq, -ceq (case-sensitive)

$arr = 1, 2, 3
3 -in $arr             # True
$arr -contains 2       # True

# Switch
switch ($day) {
    "Mon" { "Start of week" }
    "Fri" { "End of week" }
    { $_ -in "Sat","Sun" } { "Weekend" }
    default { "Midweek" }
}

# Switch with regex
switch -Regex ($input) {
    "^\d+$"   { "Number" }
    "^[a-z]+$" { "Lowercase word" }
}

# For loop
for ($i = 0; $i -lt 5; $i++) {
    Write-Output $i
}

# ForEach-Object (pipeline)
1..5 | ForEach-Object { $_ * 2 }

# foreach statement (faster for collections)
foreach ($item in $collection) {
    Write-Output $item
}

# While
$i = 0
while ($i -lt 5) {
    $i++
}

# Do-while / do-until
do {
    $input = Read-Host "Enter value"
} while ($input -ne "quit")

do {
    $input = Read-Host "Enter value"
} until ($input -eq "quit")

# Break and continue
foreach ($n in 1..10) {
    if ($n -eq 5) { break }     # exit loop
    if ($n % 2 -eq 0) { continue }  # skip iteration
}

Functions

# Basic function
function Say-Hello {
    param($Name)
    "Hello, $Name!"
}
Say-Hello -Name "Alice"

# Advanced function with parameter attributes
function Get-Greeting {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Name,

        [Parameter()]
        [ValidateRange(1, 120)]
        [int]$Age = 0,

        [switch]$Formal
    )

    $greeting = if ($Formal) { "Good day" } else { "Hi" }
    if ($Age -gt 0) {
        "$greeting, $Name. You are $Age years old."
    } else {
        "$greeting, $Name!"
    }
}

Get-Greeting -Name "Bob" -Age 30
Get-Greeting -Name "Dr. Smith" -Formal

# Return value (functions return everything written to pipeline)
function Add-Numbers {
    param([int]$A, [int]$B)
    return $A + $B      # explicit return
}
$result = Add-Numbers -A 3 -B 7   # 10

# Function with pipeline input
function Double-Input {
    process {
        $_ * 2
    }
}
1..5 | Double-Input    # 2, 4, 6, 8, 10

# Splatting (pass hashtable as parameters)
$params = @{
    Path    = "C:\logs"
    Recurse = $true
    Filter  = "*.log"
}
Get-ChildItem @params

Pipeline

The PowerShell pipeline passes objects, not text.

# Pipeline basics
Get-Process | Where-Object { $_.CPU -gt 10 } | Sort-Object CPU -Descending | Select-Object -First 5

# Aliases for common pipeline cmdlets
# Where-Object = where = ?
# ForEach-Object = foreach = %
# Select-Object = select

# Short form
Get-Process | ? CPU -gt 10 | sort CPU -Desc | select -First 5

# Calculated properties
Get-ChildItem | Select-Object Name, @{N="SizeMB"; E={ [math]::Round($_.Length / 1MB, 2) }}

# Group-Object
Get-Process | Group-Object Company | Sort-Object Count -Desc

# Measure-Object
Get-ChildItem -Recurse *.log | Measure-Object Length -Sum -Average -Maximum

# Tee-Object — branch pipeline
Get-Process | Tee-Object -FilePath procs.txt | Where-Object CPU -gt 5

# Out-* cmdlets
... | Out-File result.txt       # save to file
... | Out-GridView              # interactive grid (Windows)
... | Out-String                # convert to string
... | Out-Null                  # discard output

File system

# Navigation
Set-Location C:\Users          # cd
Push-Location C:\temp          # cd + push current to stack
Pop-Location                   # cd back to pushed location

# Listing
Get-ChildItem                  # ls / dir
Get-ChildItem -Recurse         # recursive
Get-ChildItem -Filter "*.ps1"  # filter by name
Get-ChildItem -Recurse -Include "*.log" -Exclude "debug*"

# File info
$f = Get-Item myfile.txt
$f.Length          # bytes
$f.LastWriteTime   # DateTime
$f.Extension       # ".txt"
$f.BaseName        # "myfile"

# Read / write
Get-Content file.txt                       # read all lines (array)
Get-Content file.txt -Raw                  # read as single string
Set-Content file.txt "Hello"               # overwrite
Add-Content file.txt "New line"            # append
"Line" | Out-File file.txt -Append        # append via pipeline

# Read large files efficiently
Get-Content bigfile.log | Where-Object { $_ -match "ERROR" }

# Create / copy / move / delete
New-Item -Path "folder" -ItemType Directory
New-Item -Path "file.txt" -ItemType File
Copy-Item source.txt dest.txt
Copy-Item folder -Destination backup -Recurse
Move-Item old.txt new.txt
Remove-Item file.txt
Remove-Item folder -Recurse -Force        # delete folder tree

# Test existence
Test-Path "C:\file.txt"            # True/False
Test-Path "C:\file.txt" -PathType Leaf      # must be file
Test-Path "C:\folder" -PathType Container   # must be directory

# Path manipulation
Split-Path "C:\folder\file.txt" -Leaf        # "file.txt"
Split-Path "C:\folder\file.txt" -Parent      # "C:\folder"
Join-Path "C:\folder" "sub" "file.txt"       # "C:\folder\sub\file.txt"
[System.IO.Path]::GetExtension("file.txt")   # ".txt"

# Temporary file/folder
$tmp = [System.IO.Path]::GetTempFileName()
$tmpDir = [System.IO.Path]::GetTempPath()

Working with CSV, JSON, XML

# CSV
$data = Import-Csv employees.csv
$data | Where-Object { $_.Department -eq "IT" } | Export-Csv it.csv -NoTypeInformation

# Create CSV from objects
$records = @(
    [pscustomobject]@{ Name="Alice"; Score=95 }
    [pscustomobject]@{ Name="Bob";   Score=87 }
)
$records | Export-Csv results.csv -NoTypeInformation

# JSON
$json = '{"name":"Alice","age":30}'
$obj = $json | ConvertFrom-Json
$obj.name      # "Alice"

$hash = @{ Name = "Bob"; Age = 25 }
$hash | ConvertTo-Json         # {"Name":"Bob","Age":25}
$hash | ConvertTo-Json -Depth 5   # deep objects

# Read/write JSON file
$config = Get-Content config.json | ConvertFrom-Json
$config | ConvertTo-Json | Set-Content config.json

# XML
[xml]$doc = Get-Content data.xml
$doc.root.item           # navigate nodes
$doc.SelectNodes("//item[@id='1']")  # XPath

Error handling

# Terminating vs non-terminating errors
# -ErrorAction: Continue (default), Stop, SilentlyContinue, Ignore

# Make all errors terminating globally
$ErrorActionPreference = "Stop"

# Per-command
Get-Item "missing.txt" -ErrorAction SilentlyContinue

# Try / Catch / Finally
try {
    $result = 1 / 0
    Get-Item "missing.txt" -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
    Write-Error "File not found: $_"
}
catch [System.DivideByZeroException] {
    Write-Warning "Division by zero"
}
catch {
    Write-Error "Unexpected error: $($_.Exception.Message)"
}
finally {
    Write-Output "Always runs"
}

# $? — success of last command (True/False)
Get-Process notepad -ErrorAction SilentlyContinue
if (-not $?) { "Process not found" }

# $Error — array of recent errors
$Error[0]                  # most recent error
$Error[0].Exception.Message

# Trap (legacy; prefer try/catch)
trap {
    Write-Error "Trapped: $_"
    continue
}

Processes and services

# Processes
Get-Process                                  # all processes
Get-Process -Name "chrome"                   # by name
Get-Process | Sort-Object WorkingSet -Desc | Select -First 10  # top 10 by RAM
Stop-Process -Name "notepad"                 # kill by name
Stop-Process -Id 1234                        # kill by PID
Start-Process "notepad.exe"
Start-Process "cmd.exe" -ArgumentList "/c dir" -Wait -NoNewWindow

# Run and capture output
$out = & cmd.exe /c "ipconfig"
$out = Invoke-Expression "git status"

# Services
Get-Service                                  # all services
Get-Service -Name "wuauserv"                 # Windows Update
Start-Service -Name "wuauserv"
Stop-Service  -Name "wuauserv"
Restart-Service -Name "wuauserv"
Set-Service -Name "wuauserv" -StartupType Automatic

# Scheduled tasks
Get-ScheduledTask
Register-ScheduledTask -TaskName "MyTask" -Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument ".\script.ps1") -Trigger (New-ScheduledTaskTrigger -Daily -At "08:00")

Registry

# Navigate like a file system
Set-Location HKCU:\Software
Get-ChildItem HKLM:\SOFTWARE\Microsoft

# Read values
Get-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Version"
(Get-ItemProperty "HKCU:\Software\MyApp").Version

# Write values
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Debug" -Value 1
New-Item -Path "HKCU:\Software\MyApp" -Force
New-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Setting" -Value "on" -PropertyType String

# Delete
Remove-ItemProperty -Path "HKCU:\Software\MyApp" -Name "OldSetting"
Remove-Item -Path "HKCU:\Software\OldApp" -Recurse

Remoting and jobs

# Enable remoting (run as admin)
Enable-PSRemoting -Force

# Run command on remote machine
Invoke-Command -ComputerName server01 -ScriptBlock { Get-Process }

# Interactive session
Enter-PSSession -ComputerName server01
Exit-PSSession

# Multiple machines
Invoke-Command -ComputerName srv1, srv2, srv3 -ScriptBlock {
    [pscustomobject]@{
        Computer = $env:COMPUTERNAME
        CPU = (Get-Process | Measure-Object CPU -Sum).Sum
    }
}

# Background jobs
$job = Start-Job -ScriptBlock { Get-ChildItem C:\ -Recurse }
Get-Job                          # list jobs
Wait-Job -Id $job.Id             # wait for completion
Receive-Job -Id $job.Id          # get output
Remove-Job -Id $job.Id

# Parallel execution (PowerShell 7+)
1..10 | ForEach-Object -Parallel {
    Start-Sleep -Seconds $_
    "Done: $_"
} -ThrottleLimit 4

Modules and profiles

# Find modules
Find-Module -Name "PSReadLine"
Find-Module -Tag "Security"

# Install / import
Install-Module -Name "Az" -Scope CurrentUser
Import-Module Az
Get-Module                          # list imported
Get-Module -ListAvailable           # all installed

# Profile — runs at startup
$PROFILE                            # path to profile script
Test-Path $PROFILE                  # check if exists
New-Item -Path $PROFILE -Force      # create
notepad $PROFILE                    # edit

# Common profile customizations
Set-Alias ll Get-ChildItem
function prompt { "PS $($PWD.Path)> " }
$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'

Useful one-liners

# Find large files
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt 100MB } |
    Sort-Object Length -Desc |
    Select-Object FullName, @{N="MB";E={[math]::Round($_.Length/1MB,1)}}

# Search file contents (like grep)
Select-String -Path "C:\logs\*.log" -Pattern "ERROR" -CaseSensitive

# Get disk usage by folder
Get-ChildItem C:\Users -Directory |
    ForEach-Object { [pscustomobject]@{
        Folder = $_.Name
        SizeGB = [math]::Round((Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum / 1GB, 2)
    }} | Sort-Object SizeGB -Desc

# List open ports
Get-NetTCPConnection -State Listen | Select LocalPort, @{N="Process";E={(Get-Process -Id $_.OwningProcess).Name}}

# Kill all instances of a process
Get-Process -Name "chrome" | Stop-Process -Force

# Bulk rename files
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace "old","new" }

# Download a file
Invoke-WebRequest "https://example.com/file.zip" -OutFile "file.zip"

# Get public IP
(Invoke-RestMethod "https://api.ipify.org?format=json").ip

# Check if admin
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

# Elapsed time for a block
$sw = [System.Diagnostics.Stopwatch]::StartNew()
# ... do work ...
$sw.Elapsed.TotalSeconds

# Base64 encode/decode
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("hello"))
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("aGVsbG8="))

Common mistakes

Mistake Wrong Right
String comparison $a == $b $a -eq $b
Null check $x == $null $x -eq $null or $null -eq $x
Boolean values $active = true $active = $true
Array empty check if ($arr) if ($arr.Count -gt 0)
Last array element $arr[$arr.Length-1] $arr[-1]
Suppress output $x = Some-Cmdlet (might leak) $null = Some-Cmdlet
Force string conversion [string]$obj (may be truncated) `$obj
Admin check Running without elevation silently fails Always check admin status for system changes

PowerShell 5 vs PowerShell 7

Feature Windows PowerShell 5.1 PowerShell 7+
Cross-platform Windows only Windows, Linux, macOS
Parallel ForEach No ForEach-Object -Parallel
Null coalescing No $x ?? "default"
Null conditional No $obj?.Property
Ternary operator No $cond ? "yes" : "no"
Pipeline chain No cmd1 && cmd2 / cmd1 || cmd2
Error view Full Concise (default)
Select-String context Limited -Context improved
.NET version .NET Framework 4.x .NET 8+
Get-Error No Yes (detailed error info)
Import-Excel etc. Same Same (cross-platform modules)

FAQ

Q: How do I run a PowerShell script?
Set execution policy first: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser. Then run with .\script.ps1. The RemoteSigned policy allows local scripts and requires downloaded scripts to be signed.

Q: What's the difference between Write-Output and Write-Host?
Write-Output sends objects to the pipeline — they can be captured, piped, or redirected. Write-Host writes directly to the console and bypasses the pipeline. Use Write-Output in scripts; use Write-Host only for console-only messages (progress, colour output) that should never be captured.

Q: How do I run PowerShell commands as administrator?
Right-click PowerShell and select "Run as administrator", or from code: Start-Process powershell -Verb RunAs -ArgumentList "-Command", "Your-Command". Check in script: ([Security.Principal.WindowsPrincipal]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator).

Q: How do I pass variables to Invoke-Command on a remote machine?
Use the $using: scope modifier: Invoke-Command -ComputerName srv1 -ScriptBlock { Get-Process $using:processName }. Alternatively, pass them via the -ArgumentList parameter and receive with param() inside the script block.

Q: PowerShell or Python for automation?
PowerShell is the right choice when you're managing Windows systems, Active Directory, Azure, or Microsoft 365 — it has deep native integration. Python is better for cross-platform tasks, data processing, or when you need a rich ecosystem of third-party libraries. Many sysadmins use both: PowerShell for Windows ops, Python for everything else.

Q: How do I find what cmdlet does something?
Get-Command -Verb Get -Noun *Process* — search by verb/noun. Get-Help about_* — list conceptual help topics. Get-Command | Where-Object { $_.Definition -match "something" } — search by definition. The PowerShell Gallery and Find-Module are your friends for third-party modules.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools