Table of contents
- PowerShell: The Complete Command Reference
- Concepts
- Getting Started & Help System
- Variables & Data Types
- Operators
- Strings
- Arrays & Hash Tables
- Control Flow
- Functions & Scripts
- Pipeline & Object Manipulation
- File System
- Processes & Services
- Networking
- Error Handling
- Modules, Profiles & Package Management
- Remoting & Security
- Registry, Scheduled Tasks & Event Log
- Quick Reference
- Summary
PowerShell: The Complete Command Reference
PowerShell is a cross-platform task automation shell built on top of the .NET runtime. Unlike traditional shells that pass text between commands, PowerShell passes objects — structured data with properties and methods. This fundamental difference makes it incredibly powerful for system administration, DevOps, and scripting on both Windows and Linux/macOS.
Whether you are running your first Get-Help command or building multi-machine automation pipelines, this reference covers everything from core syntax to advanced remoting, error handling, and scheduled tasks.
Concepts
Before diving in, here are the key concepts you will encounter throughout PowerShell:
Cmdlet — A compiled .NET command following the Verb-Noun naming convention (e.g., Get-Process, Set-Item). These are the building blocks of PowerShell.
Pipeline — The | character connects cmdlets so the output objects from one command flow directly into the next, without serialising to text first.
Object — Everything in PowerShell is a .NET object. A process, a file, a date — all are objects with properties (data) and methods (actions you can call).
Provider — PowerShell providers expose different data stores (file system, registry, environment variables, certificates) through a consistent path-based interface, so you can cd into HKLM:\SOFTWARE just like a folder.
Module — A reusable package of cmdlets, functions, variables, and help files. Modules are installed from the PSGallery or local paths and imported into your session.
Script Block — A block of code wrapped in { } that can be passed around, invoked later, or sent to a remote machine.
Execution Policy — A safety mechanism that controls which scripts can run. It is not a security boundary, but a safeguard against accidental script execution.
Pipeline Variable $_ — Inside ForEach-Object and Where-Object, $_ (also $PSItem) refers to the current object being processed.
Type Accelerator — A shorthand alias for a full .NET type, such as [int] for System.Int32 or [datetime] for System.DateTime.
Getting Started & Help System
Help Commands
PowerShell has a rich built-in help system. Always start here when you encounter an unfamiliar cmdlet.
Get-Help Get-Process # Full help for a cmdlet
Get-Help Get-Process -Examples # Show usage examples only
Get-Help Get-Process -Detailed # Parameter details and descriptions
Get-Help Get-Process -Online # Open documentation in browser
Get-Help *service* # Search all help topics matching a keyword
Update-Help # Download the latest help files
Discovery Commands
Get-Command # List all available commands
Get-Command -Verb Get # Filter by verb
Get-Command -Noun Service # Filter by noun
Get-Command *process* # Wildcard search
Get-Alias ls # Look up what an alias points to
Get-Member # Show properties and methods of an object
Get-Process | Get-Member # Inspect what Get-Process returns
Version & Environment
$PSVersionTable # Full version information table
$PSVersionTable.PSVersion # Just the version number
$Host.Version # Host application version
$PSHOME # PowerShell installation directory
$env:PATH # Read an environment variable
$env:COMPUTERNAME # Machine name
[System.Environment]::OSVersion # OS version info
Execution Policy
Get-ExecutionPolicy # Current effective policy
Get-ExecutionPolicy -List # Policy for every scope
Set-ExecutionPolicy RemoteSigned # Allow local + signed remote scripts
Set-ExecutionPolicy Bypass -Scope Process # Bypass for this session only
Set-ExecutionPolicy Unrestricted -Force # No restrictions (use with caution)
Unblock-File .\script.ps1 # Unblock a downloaded script
Common Aliases
PowerShell ships with many aliases for familiarity. You can always use the full cmdlet name for clarity in scripts.
| Alias | Full Cmdlet |
|---|---|
| ls, dir, gci | Get-ChildItem |
| cd, sl | Set-Location |
| cat, gc | Get-Content |
| ps, gps | Get-Process |
| kill, spps | Stop-Process |
| cp, copy | Copy-Item |
| mv, move | Move-Item |
| rm, del | Remove-Item |
| echo | Write-Output |
| cls | Clear-Host |
| man | Get-Help |
| measure | Measure-Object |
Variables & Data Types
Variable Basics
Variables in PowerShell start with $. They are dynamically typed by default, but can be explicitly typed.
$name = "Alice" # String
$age = 30 # Integer
$pi = 3.14 # Double
$flag = $true # Boolean
$nothing = $null # Null
Remove-Variable name # Delete a variable
Get-Variable # List all variables in scope
Get-Variable name # Get a specific variable object
Special Variables
$_ / $PSItem # Current pipeline object (inside ForEach-Object / Where-Object)
$? # $true if last command succeeded, $false if it failed
$LASTEXITCODE # Exit code of the last native (non-PS) process
$Error # Array of all errors in the current session
$Error[0] # Most recent error
$args # Array of unnamed arguments passed to a script
$MyInvocation # Info about the currently running script or function
$PSScriptRoot # Directory of the currently executing script
$PSCommandPath # Full path of the currently executing script
$HOME # Current user's home directory
$PWD # Current working directory (same as Get-Location)
Type Casting
You can cast values to explicit types using type accelerators in square brackets.
[int]$n = '42' # Parse string as integer
[string]$s = 100 # Convert number to string
[datetime]$d = '2024-01-01' # Parse string as date
[double]$f = '3.14'
$x.GetType() # Inspect the type of any variable
$x -is [string] # Returns $true if $x is a string
$x -as [int] # Safe cast — returns $null on failure instead of throwing
The common type accelerators are summarised below:
| Accelerator | Full Type | Description |
|---|---|---|
| [string] | System.String | Text value |
| [int] | System.Int32 | 32-bit integer |
| [long] | System.Int64 | 64-bit integer |
| [double] | System.Double | Floating-point number |
| [bool] | System.Boolean | True or false |
| [datetime] | System.DateTime | Date and time value |
| [hashtable] | System.Collections.Hashtable | Key-value collection |
| [array] | System.Array | Ordered list |
| [regex] | System.Text.RegularExpressions.Regex | Regular expression |
| [psobject] | System.Management.Automation.PSObject | Generic PS object |
| [scriptblock] | System.Management.Automation.ScriptBlock | Executable code block |
| [ipaddress] | System.Net.IPAddress | IP address value |
Scope Modifiers
| Modifier | Scope | Visibility |
|---|---|---|
| $global: | Global | Accessible everywhere in the session |
| $local: | Local | Current scope only (default) |
| $script: | Script | Entire script file |
| $private: | Private | Current scope, hidden from children |
$global:counter = 0 # Readable from any scope in the session
function Increment {
$global:counter++
}
Operators
Comparison Operators
| Operator | Meaning | Example |
|---|---|---|
| -eq | Equal | 'a' -eq 'a' |
| -ne | Not equal | 1 -ne 2 |
| -gt | Greater than | 5 -gt 3 |
| -ge | Greater than or equal | 5 -ge 5 |
| -lt | Less than | 2 -lt 4 |
| -le | Less than or equal | 3 -le 3 |
| -like | Wildcard match | 'hello' -like 'hel*' |
| -match | Regex match | 'abc' -match '[a-z]+' |
| -contains | Collection contains value | 1,2,3 -contains 2 |
| -in | Value in collection | 2 -in 1,2,3 |
| -is | Type check | 'hi' -is [string] |
By default, string comparisons are case-insensitive. Prefix an operator with c to make it case-sensitive: -ceq, -clike, -cmatch.
Logical Operators
$a -and $b # Both must be true
$a -or $b # At least one must be true
-not $a / !$a # Negation
$a -xor $b # Exactly one must be true (exclusive or)
Arithmetic & Assignment
# Arithmetic
$x + $y # Addition (also string concatenation)
$x - $y # Subtraction
$x * $y # Multiplication
$x / $y # Division
$x % $y # Modulo (remainder)
$x ** 2 # Exponentiation (PowerShell 7+)
# Compound assignment
$x += 5
$x -= 2
$x *= 3
$x /= 4
$x %= 2
# Increment / Decrement
$x++
$x--
# Bitwise
$x -band $y # Bitwise AND
$x -bor $y # Bitwise OR
$x -bxor $y # Bitwise XOR
-bnot $x # Bitwise NOT
$x -shl 2 # Shift left 2 bits
$x -shr 2 # Shift right 2 bits
String Operators
"Hello" + " World" # Concatenation
"Value: {0:N2}" -f 1234.5 # String format (like printf)
"abc" -replace "a", "x" # Regex replace → "xbc"
"a,b,c" -split "," # Split into array
1,2,3 -join "-" # Join array → "1-2-3"
$x ?? "default" # Null-coalescing (PS 7+)
$obj?.Property # Null-conditional member access (PS 7+)
1..10 # Range operator → array 1 to 10
Strings
String Creation
$name = "Alice"
"Hello $name" # Double quotes — variable interpolation
'Hello $name' # Single quotes — literal, no interpolation
"Tab:`t Newline:`n" # Escape sequences inside double quotes
# Here-string (preserves whitespace and newlines, double-quote variant interpolates)
$multiLine = @"
Dear $name,
Welcome to PowerShell.
"@
$literal = @'
No $interpolation here.
'@
String Methods
$s = " Hello, World! "
$s.Length # Character count (includes whitespace)
$s.ToUpper() # " HELLO, WORLD! "
$s.ToLower() # " hello, world! "
$s.Trim() # "Hello, World!"
$s.TrimStart() # "Hello, World! "
$s.TrimEnd() # " Hello, World!"
$s.Replace("World", "PS") # Replace substring
$s.Split(",") # Returns string array
$s.Contains("Hello") # $true
$s.StartsWith(" Hello") # $true
$s.EndsWith("! ") # $true
$s.IndexOf("World") # Character position of first match
$s.Substring(2, 5) # Extract 5 chars starting at position 2
$s.PadLeft(30) # Right-align in 30-char field
$s.PadRight(30, '-') # Left-align, pad with dashes
String Formatting
"Hello {0}, you are {1} years old." -f "Alice", 30
"Pi is approximately {0:F4}" -f [Math]::PI # "3.1416"
"Today: {0:yyyy-MM-dd}" -f (Get-Date)
"{0,10}" -f "right" # Right-align in 10 chars
"{0,-10}" -f "left" # Left-align in 10 chars
[string]::Join(", ", @("a","b","c")) # "a, b, c"
[string]::Format("{0} and {1}", $a, $b)
"hello world" -replace "\bworld\b", "PowerShell" # Regex replace
"abc123" -match "\d+" # Returns $true
$Matches[0] # "123" — last regex match result
"one two three" -split "\s+" # Split on any whitespace
Escape Characters
| Sequence | Meaning |
|---|---|
| `n | Newline |
| `t | Tab |
| `r | Carriage return |
| `` | Literal backtick |
| `$ | Literal dollar sign |
| `" | Literal double quote |
| `0 | Null character |
| `a | Alert / bell |
| `b | Backspace |
Arrays & Hash Tables
Arrays
$arr = 1, 2, 3, 4, 5 # Comma-separated list
$arr = @("a", "b", "c") # Array literal syntax
$arr = @() # Empty array
# Access
$arr[0] # First element
$arr[-1] # Last element
$arr[1..3] # Slice — elements at index 1, 2, 3
# Properties
$arr.Count # Number of elements
$arr.Length # Same as Count
# Modify
$arr += 6 # Append (creates new array internally)
$arr -contains 3 # $true if 3 is in the array
# Mutable list (more efficient for frequent appends)
[System.Collections.ArrayList]$list = @()
$list.Add("item")
$list.Remove("item")
$list.AddRange(@(1,2,3))
# Operations
$arr | Sort-Object # Sort ascending
$arr | Sort-Object -Descending
$arr | Select-Object -Unique # Remove duplicates
$arr | Measure-Object -Sum -Average -Max -Min
Hash Tables
$h = @{ Name = "Bob"; Age = 25; City = "NYC" }
# Access
$h["Name"] # Bracket access
$h.Age # Dot notation
# Modify
$h["Email"] = "bob@example.com" # Add or update key
$h.Remove("City") # Remove a key
# Inspection
$h.Keys # All keys
$h.Values # All values
$h.ContainsKey("Name") # $true
$h.Count # Number of key-value pairs
# Ordered hash table (preserves insertion order)
[ordered]@{ First = 1; Second = 2; Third = 3 }
# Iterate
foreach ($key in $h.Keys) {
Write-Host "$key = $($h[$key])"
}
PSCustomObject
PSCustomObject lets you build lightweight structured objects on the fly, which is extremely useful for pipeline output and reporting.
$person = [PSCustomObject]@{
Name = "Eve"
Score = 98
Grade = "A"
}
# Access properties
$person.Name
$person.Score
# Add a new property at runtime
$person | Add-Member -MemberType NoteProperty -Name "Pass" -Value $true
# Use in pipeline
$person | Select-Object Name, Score
$people | Sort-Object Score -Descending
$people | Export-Csv report.csv -NoTypeInformation
Control Flow
If / ElseIf / Else
if ($score -ge 90) {
Write-Host "A"
} elseif ($score -ge 80) {
Write-Host "B"
} elseif ($score -ge 70) {
Write-Host "C"
} else {
Write-Host "F"
}
# Ternary operator (PowerShell 7+)
$result = $score -ge 60 ? "Pass" : "Fail"
Switch
switch ($color) {
"red" { Write-Host "Stop" }
"green" { Write-Host "Go" }
"amber" { Write-Host "Slow" }
default { Write-Host "Unknown color" }
}
# Switch with flags
switch -Wildcard ($input) {
"err*" { "Error message" }
"warn*"{ "Warning message" }
}
switch -Regex ($input) {
'^\d+$' { "Pure number" }
'^[a-z]' { "Starts with lowercase" }
}
# Switch on multiple values at once
switch (1, 2, 3) {
1 { "one" }
2 { "two" }
}
Loops
# Classic for loop
for ($i = 0; $i -lt 10; $i++) {
Write-Host $i
}
# foreach — iterate a collection
foreach ($item in $collection) {
Write-Host $item
}
# ForEach-Object — pipeline iteration
$arr | ForEach-Object { $_ * 2 }
# while
while ($x -lt 10) { $x++ }
# do-while (executes at least once)
do { $x++ } while ($x -lt 10)
# do-until
do { $x++ } until ($x -ge 10)
# Parallel ForEach (PowerShell 7+)
1..20 | ForEach-Object -Parallel {
Start-Sleep 1
"Done: $_"
} -ThrottleLimit 5
Loop Control
break # Exit the current loop immediately
continue # Skip the rest of the current iteration
return # Exit the current function or script
exit 0 # Exit the PowerShell process with exit code 0
throw "Something went wrong" # Raise a terminating error
Functions & Scripts
Basic Function
function Greet {
param(
[string]$Name = "World"
)
Write-Output "Hello, $Name!"
}
Greet # Hello, World!
Greet -Name "Alice" # Hello, Alice!
"Bob" | Greet # Hello, Bob! (with ValueFromPipeline)
Advanced Function
Adding [CmdletBinding()] promotes a function to a full cmdlet, enabling -Verbose, -Debug, -WhatIf, and -Confirm automatically.
function Invoke-Report {
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$ComputerName,
[ValidateRange(1, 100)]
[int]$Limit = 10
)
begin {
Write-Verbose "Starting report..."
}
process {
if ($PSCmdlet.ShouldProcess($ComputerName, "Generate report")) {
Write-Verbose "Processing $ComputerName"
# ... logic here
}
}
end {
Write-Verbose "Report complete."
}
}
The three blocks serve different roles:
begin— Runs once before the pipeline starts. Use it for setup.process— Runs once per piped object. This is where the main logic lives.end— Runs once after all pipeline objects have been processed. Use it for cleanup or final output.
Parameter Validation
param(
[ValidateNotNullOrEmpty()]
[string]$Name,
[ValidateRange(1, 100)]
[int]$Count,
[ValidateLength(3, 20)]
[string]$Username,
[ValidatePattern("^[A-Za-z0-9_]+$")]
[string]$Identifier,
[ValidateSet("Low", "Medium", "High")]
[string]$Priority,
[ValidateScript({ Test-Path $_ })]
[string]$FilePath,
[AllowNull()]
[string]$OptionalValue
)
Script Parameters
Parameters defined at the top of a .ps1 file work exactly the same way as function parameters.
# deploy.ps1
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Environment,
[switch]$DryRun,
[Parameter(ValueFromPipeline = $true)]
[string[]]$ServerList
)
Run it with:
.\deploy.ps1 -Environment Production
.\deploy.ps1 -Environment Staging -DryRun
Calling & Dot-Sourcing
.\script.ps1 -Param value # Run script in child scope
. .\functions.ps1 # Dot-source: imports all functions into current scope
& $scriptBlock # Invoke a script block
& ".\path with spaces\script.ps1" # Call operator for paths with spaces
Invoke-Command -ScriptBlock { Get-Process }
Invoke-Expression "Get-Date" # Execute a string as code (use sparingly)
Pipeline & Object Manipulation
Pipeline Basics
The pipeline passes full .NET objects between cmdlets. Properties stay intact throughout the chain.
Get-Process | Where-Object { $_.CPU -gt 100 }
Get-Process | Where-Object Name -eq "chrome" # Simplified syntax (PS 3+)
Get-Service | Where-Object Status -eq Running
Get-Process | Sort-Object CPU -Descending
Get-Process | Select-Object -First 10
Get-Process | Select-Object Name, CPU, WS # Choose specific properties
Get-Process | ForEach-Object { $_.Kill() }
Grouping & Aggregation
Get-Process | Group-Object Company
Get-Process | Measure-Object WorkingSet -Sum -Average -Max -Min
Get-ChildItem | Group-Object Extension | Sort-Object Count -Descending
Get-EventLog System | Group-Object EntryType
1..100 | Measure-Object -Sum
Select & Format
# Calculated properties
Get-Process | Select-Object Name, @{ N = "MB"; E = { [math]::Round($_.WS / 1MB, 2) } }
# Formatting (for display only — do not pipe Format-* to other cmdlets)
Get-Process | Format-Table Name, CPU, WS -AutoSize
Get-Process | Format-List * # All properties, list view
Get-Process | Format-Wide Name -Column 4
# Export
Get-Process | Export-Csv processes.csv -NoTypeInformation
Get-Process | ConvertTo-Json | Set-Content procs.json
Get-Process | Out-File output.txt -Encoding UTF8
Get-Process | Out-GridView # Interactive GUI grid (Windows)
Output Redirection
Get-Process > procs.txt # Redirect stdout (overwrite)
Get-Process >> procs.txt # Redirect stdout (append)
Get-Process 2> errors.txt # Redirect stderr stream
Get-Process 2>&1 # Merge stderr into stdout
Get-Process *> all.txt # Redirect all streams
Get-Process | Out-Null # Discard all output
File System
Navigation
Get-Location # Print current directory (pwd)
Set-Location C:\Users\Alice # Change directory (cd)
Set-Location ~ # Go to home directory
Set-Location - # Go back to previous location (PS 6+)
Push-Location .\subdir # Save current dir and navigate
Pop-Location # Return to saved directory
Get-ChildItem # List contents (ls / dir)
Get-ChildItem -Hidden # Include hidden items
Get-ChildItem -Recurse -Filter *.log
File Operations
New-Item file.txt -ItemType File
New-Item logs -ItemType Directory
Copy-Item src.txt dst.txt
Copy-Item C:\src C:\dst -Recurse # Copy entire directory tree
Move-Item old.txt new.txt
Rename-Item report.txt report_v2.txt
Remove-Item file.txt
Remove-Item .\temp -Recurse -Force # Delete directory and all contents
Test-Path C:\file.txt # Returns $true or $false
Test-Path C:\file.txt -PathType Leaf # File only
Test-Path C:\folder -PathType Container # Directory only
Reading & Writing Files
Get-Content file.txt # Read all lines as array
Get-Content file.txt -Raw # Read as single string
Get-Content big.txt -TotalCount 10 # First 10 lines
Get-Content big.txt -Tail 20 # Last 20 lines
Get-Content log.txt -Wait # Tail -f equivalent
Set-Content file.txt "Hello World" # Overwrite file
Add-Content file.txt "More text" # Append to file
"Line 1", "Line 2" | Out-File file.txt -Encoding UTF8
[IO.File]::ReadAllText("file.txt") # Fast .NET read
[IO.File]::WriteAllLines("out.txt", $lines)
Path Operations
Split-Path C:\dir\file.txt # Returns "C:\dir"
Split-Path C:\dir\file.txt -Leaf # Returns "file.txt"
Split-Path C:\dir\file.txt -Extension # Returns ".txt" (PS 7+)
Join-Path C:\dir "subdir\file.txt" # Build a path safely
Resolve-Path .\relative\path # Convert to absolute path
[IO.Path]::GetFileName("C:\dir\file.txt") # "file.txt"
[IO.Path]::GetExtension("file.txt") # ".txt"
[IO.Path]::GetFileNameWithoutExtension("f.txt") # "f"
[IO.Path]::Combine("C:\dir", "file.txt") # Cross-platform join
Processes & Services
Processes
Get-Process # All running processes
Get-Process chrome # By name (supports wildcards)
Get-Process -Id 1234 # By PID
Stop-Process -Name notepad
Stop-Process -Id 1234 -Force
Start-Process notepad.exe
Start-Process cmd -ArgumentList "/c dir C:\" -Wait
Start-Process powershell -Verb RunAs # Launch elevated (as Administrator)
Wait-Process -Name notepad -Timeout 60
# Top 10 by CPU or memory
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Get-Process | Sort-Object WS -Descending | Select-Object -First 10
# Total memory used by all chrome processes (MB)
(Get-Process chrome | Measure-Object WS -Sum).Sum / 1MB
Services
Get-Service # All services
Get-Service -Name WinRM # Specific service
Get-Service | Where-Object Status -eq Running
Start-Service -Name Spooler
Stop-Service -Name Spooler -Force
Restart-Service -Name Spooler
Suspend-Service -Name Spooler # Pause (if supported)
Set-Service -Name Spooler -StartupType Automatic
Set-Service -Name Spooler -StartupType Disabled
New-Service -Name "MySvc" -BinaryPathName "C:\MySvc\MySvc.exe" -DisplayName "My Service"
Remove-Service -Name "MySvc" # PS 6+
WMI & CIM (System Information)
CIM cmdlets (Get-CimInstance) are the modern replacement for the older Get-WmiObject and work over WSMan instead of DCOM.
Get-CimInstance Win32_OperatingSystem # OS details
Get-CimInstance Win32_ComputerSystem # Hostname, RAM, domain
Get-CimInstance Win32_LogicalDisk # Drive space
Get-CimInstance Win32_NetworkAdapter # Network adapters
Get-CimInstance Win32_Bios # BIOS info
Get-CimInstance Win32_Process | Select-Object Name, CommandLine
Background Jobs
$job = Start-Job { Get-Process } # Run in background
Get-Job # List jobs
$job.State # Running, Completed, Failed
Receive-Job $job # Get output (clears by default)
Receive-Job $job -Keep # Get output without clearing
Wait-Job $job # Block until job finishes
Stop-Job $job
Remove-Job $job
# Wait for all jobs and collect results
Get-Job | Wait-Job | Receive-Job
Networking
Network Testing
Test-Connection google.com # Ping (4 requests)
Test-Connection google.com -Count 10 -Quiet # Returns $true/$false
Test-NetConnection google.com -Port 443 # TCP connectivity test
Test-NetConnection -ComputerName DC1 -TraceRoute
Resolve-DnsName google.com # DNS lookup
Resolve-DnsName google.com -Type MX # Mail exchange records
Resolve-DnsName google.com -Type A # A records only
Network Adapters & Configuration
Get-NetAdapter # List all NICs
Get-NetAdapter | Where-Object Status -eq Up
Get-NetIPAddress # All IP addresses
Get-NetIPConfiguration # Full config per adapter
Get-NetRoute # Routing table
Get-DnsClientServerAddress # Configured DNS servers
Web Requests
$response = Invoke-WebRequest "https://example.com"
$response.StatusCode
$response.Content
$response.Headers
# REST API call
$data = Invoke-RestMethod "https://api.github.com/users/octocat"
$data.login
$data.public_repos
# POST with JSON body and auth header
$body = @{ title = "New Issue"; body = "Details here" } | ConvertTo-Json
$headers = @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" }
Invoke-RestMethod "https://api.github.com/repos/owner/repo/issues" `
-Method POST -Headers $headers -Body $body
File Download & JSON
# Download a file
Invoke-WebRequest "https://example.com/file.zip" -OutFile ".\file.zip"
# Parse JSON from file
$config = Get-Content config.json | ConvertFrom-Json
$config.database.host
# Serialize to JSON
$obj | ConvertTo-Json -Depth 10
$obj | ConvertTo-Json | Set-Content output.json
# Work with CSV
Import-Csv data.csv | Where-Object { $_.Age -gt 30 }
$objects | Export-Csv report.csv -NoTypeInformation
Netstat
netstat -an # All connections and listening ports
netstat -b # Show executable involved in each connection (requires admin)
netstat -o # Show owning process ID (PID)
netstat -s # Per-protocol statistics
netstat -r # Routing table (same as route print)
netstat -f # Show fully qualified domain names for remote addresses
netstat -ano # All connections + PID + no DNS resolution (most common)
netstat -ano | findstr :80 # Filter by port 80
netstat -ano | findstr ESTABLISHED # Only established connections
netstat -ano | findstr LISTENING # Only listening ports
Error Handling
Try / Catch / Finally
try {
Get-Item "C:\does-not-exist.txt" -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Error "File not found: $($_.Exception.Message)"
}
catch [System.UnauthorizedAccessException] {
Write-Error "Access denied."
}
catch {
Write-Error "Unexpected error: $($_.Exception.Message)"
Write-Verbose $_.ScriptStackTrace
}
finally {
# Always executes, even if an exception was thrown
Write-Host "Cleanup complete."
}
Error Action Preferences
| Value | Behavior |
|---|---|
| Continue | Display error and continue (default) |
| Stop | Throw a terminating error |
| SilentlyContinue | Suppress error, continue silently |
| Inquire | Prompt the user for action |
| Ignore | Suppress error, do not record in $Error |
# Session-wide preference
$ErrorActionPreference = 'Stop'
# Per-command override
Get-Item x -ErrorAction SilentlyContinue
# Capture error into a variable
Get-Item x -ErrorVariable myErr -ErrorAction SilentlyContinue
$myErr[0].Exception.Message
Debugging
Set-PSDebug -Trace 1 # Trace execution (1 = basic, 2 = verbose with variable names)
Set-PSDebug -Off # Disable tracing
Set-StrictMode -Version Latest # Error on undefined variables and bad practices
Write-Verbose "Details here" -Verbose # Only visible when -Verbose is specified
Write-Debug "Debug info" -Debug # Only visible when -Debug is specified
Write-Warning "Something seems off" # Yellow warning, always visible
Write-Error "This failed" # Red error, non-terminating by default
# Inspect the error record
$Error[0].Exception.Message
$Error[0].InvocationInfo.ScriptLineNumber
$Error[0].ScriptStackTrace
$Error.Clear() # Reset the error log
Modules, Profiles & Package Management
Module Commands
Get-Module # Currently imported modules
Get-Module -ListAvailable # All installed modules
Import-Module ActiveDirectory
Import-Module .\MyModule.psm1 # Load from file path
Remove-Module MyModule
Get-Command -Module PSReadLine # Commands from a specific module
A module typically has this structure:
MyModule/
├── MyModule.psd1 ← Manifest (metadata, exported members, dependencies)
└── MyModule.psm1 ← Module code (functions, variables)
New-ModuleManifest MyModule.psd1 -RootModule MyModule.psm1 -Author "Your Name"
Profiles
Profiles are scripts that run automatically when PowerShell starts, letting you customise your environment.
$PROFILE # Current user, current host profile
$PROFILE.CurrentUserAllHosts # Current user, all PS hosts
$PROFILE.AllUsersCurrentHost # All users, current host
$PROFILE.AllUsersAllHosts # All users, all hosts
Test-Path $PROFILE # Check if profile exists
New-Item $PROFILE -Force -ItemType File # Create it
notepad $PROFILE # Edit in Notepad
code $PROFILE # Edit in VS Code
PowerShellGet & PSGallery
Find-Module Pester # Search the PowerShell Gallery
Install-Module Pester -Force
Install-Module Az -Scope CurrentUser # Install without administrator rights
Update-Module Pester
Uninstall-Module Pester
Get-PSRepository # Registered repositories
# Register a private repository
Register-PSRepository -Name "Internal" -SourceLocation "\\server\share\modules"
Publish-Module -Path .\MyModule -Repository PSGallery -NuGetApiKey $key
# Windows Package Management
Get-PackageProvider
Find-Package git
Install-Package -Name git -ProviderName Chocolatey
# winget (Windows 10/11)
winget install git.git
winget upgrade --all
winget list
# Chocolatey
choco install notepadplusplus -y
choco upgrade all -y
Remoting & Security
PSRemoting Setup
# On the target machine
Enable-PSRemoting -Force
# On the connecting machine
Test-WSMan Server01
Get-Item WSMan:\localhost\Client\TrustedHosts
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "Server01,Server02"
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" # Trust all (lab use only)
Disable-PSRemoting -Force
Invoke-Command & Persistent Sessions
# One-off remote command
Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Process }
Invoke-Command -ComputerName Server01, Server02 -ScriptBlock { hostname }
# With credentials
$cred = Get-Credential
Invoke-Command -ComputerName Server01 -Credential $cred -ScriptBlock { Get-Service }
# Interactive session
Enter-PSSession -ComputerName Server01
Enter-PSSession -ComputerName Server01 -Credential $cred
Exit-PSSession
# Persistent session (state is preserved between calls)
$s = New-PSSession -ComputerName Server01
Invoke-Command -Session $s -ScriptBlock { $data = 1..10 }
Invoke-Command -Session $s -ScriptBlock { $data } # $data is still there
Get-PSSession
Remove-PSSession $s
SSH Remoting (PowerShell 7+ / Cross-Platform)
Enter-PSSession -HostName ubuntu01 -UserName admin
Invoke-Command -HostName ubuntu01 -UserName admin -ScriptBlock { uname -a }
$s = New-PSSession -HostName ubuntu01 -UserName admin -SSHTransport
Credentials
# Interactive prompt
$cred = Get-Credential
$cred = Get-Credential -Message "Enter your server password" -UserName "DOMAIN\admin"
# Programmatic (avoid storing plaintext passwords in scripts)
$pw = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
$cred = New-Object PSCredential("DOMAIN\admin", $pw)
# Store securely to disk and retrieve later
$pw | ConvertFrom-SecureString | Set-Content cred.txt
$pw = Get-Content cred.txt | ConvertTo-SecureString
Registry, Scheduled Tasks & Event Log
Registry
The registry is exposed as a drive in PowerShell, so standard Item cmdlets work on it.
# Navigate
Get-Item HKLM:\SOFTWARE\Microsoft
Get-ChildItem HKCU:\SOFTWARE
# Read values
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
(Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion).ProgramFilesDir
# Write values
Set-ItemProperty HKCU:\SOFTWARE\MyApp -Name "Theme" -Value "Dark"
New-Item HKCU:\SOFTWARE\MyApp
New-ItemProperty HKCU:\SOFTWARE\MyApp -Name "Version" -Value "1.0" -PropertyType String
# Remove
Remove-ItemProperty HKCU:\SOFTWARE\MyApp -Name "Version"
Remove-Item HKCU:\SOFTWARE\MyApp -Recurse
# Test existence
Test-Path HKCU:\SOFTWARE\MyApp
Scheduled Tasks
Get-ScheduledTask
Get-ScheduledTask -TaskName "Backup"
Start-ScheduledTask -TaskName "Backup"
Stop-ScheduledTask -TaskName "Backup"
Enable-ScheduledTask -TaskName "Backup"
Disable-ScheduledTask -TaskName "Backup"
Unregister-ScheduledTask -TaskName "Backup" -Confirm:$false
# Create a new scheduled task
$trigger = New-ScheduledTaskTrigger -Daily -At "03:00AM"
$action = New-ScheduledTaskAction `
-Execute "PowerShell.exe" `
-Argument "-NonInteractive -File C:\Scripts\backup.ps1"
$settings = New-ScheduledTaskSettingsSet -RunOnlyIfNetworkAvailable
Register-ScheduledTask `
-TaskName "DailyBackup" `
-Trigger $trigger `
-Action $action `
-Settings $settings `
-RunLevel Highest
Event Log
# Classic event log (Windows only)
Get-EventLog -LogName System -Newest 50
Get-EventLog -LogName Application -EntryType Error, Warning
Get-EventLog System -Source "Service Control Manager" -Newest 20
Clear-EventLog -LogName Application
# Modern WinEvent (more powerful, works with all log sources)
Get-WinEvent -LogName Security -MaxEvents 100
Get-WinEvent -FilterHashtable @{ LogName = "System"; Level = 2 } # Level 2 = Error
Get-WinEvent -FilterHashtable @{ LogName = "System"; Id = 7036; StartTime = (Get-Date).AddDays(-7) }
Get-WinEvent -ListLog * # All available logs
# Write to event log
New-EventLog -LogName Application -Source "MyApp"
Write-EventLog -LogName Application -Source "MyApp" -EventId 1001 `
-EntryType Information -Message "Script completed successfully."
Quick Reference
| Category | Cmdlet | Purpose |
|---|---|---|
| Process | Get-Process | List running processes |
| Process | Start-Process | Launch a new process |
| Process | Stop-Process | Kill a process |
| Service | Get-Service | List system services |
| Service | Start-Service / Stop-Service | Control service state |
| File | Get-ChildItem | List directory contents |
| File | Copy-Item / Move-Item | Copy or move files |
| File | Get-Content / Set-Content | Read or write file content |
| Pipeline | Where-Object | Filter objects |
| Pipeline | Select-Object | Select properties |
| Pipeline | Sort-Object | Sort objects |
| Pipeline | ForEach-Object | Iterate over objects |
| Network | Test-Connection | Ping a host |
| Network | Invoke-RestMethod | Call a REST API |
| Output | Write-Host | Print to console |
| Output | Export-Csv | Save objects to CSV |
Summary
PowerShell is built around three core ideas that set it apart from other shells: everything is an object, the pipeline connects commands without losing structure, and the Verb-Noun naming convention makes cmdlets discoverable. Starting with Get-Help and Get-Command gives you access to the entire ecosystem from day one.
This reference walked through the complete surface of PowerShell scripting — from variables, operators, and control flow through to functions, pipeline manipulation, file system access, process and service management, networking, error handling, remoting, and Windows-specific features like the registry, scheduled tasks, and the event log.
Use Get-Help <cmdlet> -Examples whenever you need a reminder on any of the commands shown here. PowerShell's built-in documentation is one of its greatest strengths, and it is always one command away.
