PowerShell, Unleashed: The Everything Guide (for Humans & Automation)

PowerShell is a cross-platform automation shell built on .NET with an object-based pipeline, a rich standard library of cmdlets, and first-class scripting. If you’ve ever juggled Bash, Python, and C# to glue systems together, PowerShell lets you do most of that from one console—Windows, macOS, or Linux.

Who’s this for? Admins, SREs, devs, and curious tinkerers who want a single, pragmatic guide to the PowerShell universe—from “what is a cmdlet?” to remoting, packaging, testing, and performance.

Why PowerShell

  • Objects, not text: Pipe rich .NET objects instead of parsing text. Less regex, fewer bugs.
  • Cross-platform: PowerShell 7+ runs on Windows/macOS/Linux. Same language, platform-specific modules when needed.
  • Deep OS access: Filesystem, registry, certificates, services, processes, WMI/CIM, event logs, and more via providers/cmdlets.
  • Interoperability: Call native tools, .NET APIs, REST, SSH, and use JSON/CSV/XML like a local citizen.

A 10-minute Tour

Discoverability

Get-Help Get-Process -Online       # open docs in browser
Get-Command -Noun Process           # list all *-Process cmdlets
Get-Command -ParameterName ComputerName
Get-Member -InputObject (Get-Process | Select-Object -First 1)   # inspect members

The object pipeline

Get-Service | Where-Object Status -eq Running | Sort-Object Name | Select-Object Name,Status
Get-ChildItem C:\Logs -File | Where-Object Length -gt 10MB | Remove-Item -WhatIf

Providers & PSDrives

Get-PSDrive            # FileSystem, Registry (HKLM:\), Cert:\, Env:\, Function:\ ...
Set-Location HKLM:\SOFTWARE
Get-ChildItem Cert:\CurrentUser\My | Format-Table Subject, NotAfter

Formatting vs. data shaping

Get-Process | Select-Object Name,CPU | Sort-Object CPU -Descending |
    Format-Table -AutoSize    # Format-* is for display only; don't pipe it into more logic

Shell Superpowers

Consistency: Verb-Noun

Cmdlets use approved verbs (Get, Set, New, Remove, Invoke…) and singular nouns. Autocomplete helps you guess new commands you’ve never seen.

Common parameters

Most cmdlets support -Verbose, -ErrorAction, -WhatIf, -Confirm. Try them!

Aliases (use sparingly)

ls -> Get-ChildItem; cat -> Get-Content; ps -> Get-Process
# Great at the prompt; avoid aliases in scripts for readability.

Type accelerators & .NET interop

[datetime]::UtcNow
[regex]::Match('abc123', '\d+').Value
$wc = New-Object System.Net.Http.HttpClient

Scripting Essentials

Parameters, validation & pipeline input

function Get-TopProcess {
  [CmdletBinding()]
  param(
    [int]$Count = 5,
    [Parameter(ValueFromPipeline=$true)]
    [object[]]$Process
  )
  process {
    if(-not $Process){ $Process = Get-Process }
    $Process | Sort-Object CPU -Descending | Select-Object -First $Count
  }
}

Advanced functions & ShouldProcess

function Remove-OldLog {
  [CmdletBinding(SupportsShouldProcess)]
  param([string]$Path, [int]$Days = 30)
  $cut = (Get-Date).AddDays(-$Days)
  Get-ChildItem $Path -File | Where-Object LastWriteTime -lt $cut |
    ForEach-Object {
      if ($PSCmdlet.ShouldProcess($_.FullName, "Delete")) { Remove-Item $_.FullName -Force }
    }
}

Variables & scope

$script:Var = 42; $global:Log = @(); $env:Path; $PSBoundParameters

Classes (when you need structure)

class Server {
  [string]$Name
  [string]$Role
  Server([string]$n,[string]$r){ $this.Name=$n; $this.Role=$r }
}

Errors & Debugging

Terminating vs non-terminating

$ErrorActionPreference = 'Stop'   # promote non-terminating errors to terminating
try {
  1/0
} catch {
  Write-Warning "Oops: $($_.Exception.Message)"
} finally {
  Write-Verbose "Always runs" -Verbose
}

Debugging & transcripts

Set-PSDebug -Trace 1            # lightweight tracing (turn off after!)
Start-Transcript .\session.log   # capture console I/O

Working with Data (JSON / CSV / XML)

# JSON
Invoke-RestMethod https://api.example.com/users | Where-Object active |
  ConvertTo-Json -Depth 5 | Out-File users.json

# CSV
Import-Csv .\servers.csv | Where-Object Role -eq 'web' |
  ForEach-Object { Test-Connection $_.Name -Count 1 }

# XML
[xml]$xml = Get-Content .\config.xml
$xml.configuration.appSettings.add | Select-Object key, value

Remoting & Parallelism

Windows Remoting (WinRM)

Enter-PSSession -ComputerName server01
Invoke-Command -ComputerName web01,web02 -ScriptBlock { Get-Service w3svc }

SSH-based remoting (cross-platform)

Enter-PSSession -HostName linux01 -User demo
Invoke-Command -HostName mac01 -User admin -ScriptBlock { uname -a }

Background & parallel

# Background jobs
1..10 | ForEach-Object { Start-Job { param($i) Start-Sleep 1; "Job $i" } -ArgumentList $_ } | Receive-Job -Wait

# PowerShell 7+: foreach -Parallel
$servers | ForEach-Object -Parallel { Test-Connection $_ -Count 1 } -ThrottleLimit 10

Security, Signing & Execution Policy

  • Execution Policy: Controls script launch behaviour (Get-ExecutionPolicy, Set-ExecutionPolicy). It’s not a security boundary, but a guardrail.
  • Script signing: Use a code-signing certificate; set policy to AllSigned in locked-down environments.
  • AMSI & Defender: PowerShell integrates with antimalware; keep AV and OS current.
  • Constrained Language Mode (CLM): Reduces capabilities under certain enterprise controls.

Modules, Packaging & PowerShell Gallery

# Find, install, update (PowerShellGet)
Find-Module Pester | Install-Module -Scope CurrentUser
Update-Module Pester

# Create a module
New-ModuleManifest -Path .\AwesomeTools\AwesomeTools.psd1 -RootModule AwesomeTools.psm1
# Export functions in the .psm1; publish when ready.

Prefer modules over one-off scripts for reuse/versioning. Include a manifest, semantic version, dependency list, and help.

Tooling: Profiles, PSReadLine, Style

  • Profile: Customize your shell in $PROFILE (aliases, prompt, module imports).
  • PSReadLine: Syntax highlighting, history search (Ctrl+r), predictive IntelliSense.
  • Style: Use approved verbs, singular nouns, PascalCase for functions, Verb-Noun naming, and comment-based help.
  • Help: Add examples and parameter docs with <# .SYNOPSIS ... #> blocks; surface via Get-Help.

Windows, Linux & Cloud Automation

Windows & Server

Get-Service, Get-EventLog / Get-WinEvent, Get-ScheduledTask, Get-NetAdapter
Enable-WindowsOptionalFeature -Online -FeatureName containers

Linux/macOS

# Use native tools + PowerShell objects
df -h | Out-String
Get-ChildItem /var/log | Where-Object Length -gt 1MB

Cloud & REST

# REST first
Invoke-RestMethod -Uri 'https://api.example.com/items' -Headers @{Authorization="Bearer $token"}

# Cloud modules (examples)
# Install-Module Az; Install-Module AWSPowerShell.NetCore; Install-Module GoogleCloud

Testing, Linting & CI

Pester (unit & integration tests)

Describe "Get-TopProcess" {
  It "returns N items" {
    (Get-TopProcess -Count 3).Count | Should -Be 3
  }
}

PSScriptAnalyzer (linting)

Install-Module PSScriptAnalyzer
Invoke-ScriptAnalyzer -Path .\ -Recurse -Fix

CI

Run Pester & PSScriptAnalyzer in GitHub Actions/Azure DevOps; publish modules to an internal feed or the PowerShell Gallery as part of release.

Performance Tips

  • Measure: Measure-Command and Measure-Object before “optimizing”.
  • Avoid unnecessary formatting in the middle of pipelines; shape with Select-Object until the end.
  • Prefer cmdlets over external tools when you need objects; prefer native tools when you only need raw text quickly.
  • Use ForEach-Object -Parallel (7+) or background jobs for I/O-bound fan-out.
  • Batch remote calls: Use Invoke-Command with multiple targets instead of serial loops.

Cheat Sheet

# Discover
Get-Help cmdlet -Online
Get-Command *service*
Get-Member
# Files
Get-ChildItem -Recurse | Where Length -gt 1MB
Get-Content .\log.txt -Tail 50
# JSON
Invoke-RestMethod ... | ConvertTo-Json -Depth 5
# Errors
$ErrorActionPreference = 'Stop'
try { ... } catch { $_ | Out-String }
# Remoting
Invoke-Command -ComputerName srv -ScriptBlock { hostname }
# Parallel (7+)
$items | ForEach-Object -Parallel { ... } -ThrottleLimit 10

Check your runtime with $PSVersionTable. Put your favourite tweaks in $PROFILE. Keep modules up to date.

Final note: PowerShell is best learned by doing. Open a console, run Get-Help, and start replacing fragile text parsing with resilient object pipelines. Your future self (and your on-call rota) will thank you.

Leave a Comment

Your email address will not be published. Required fields are marked *

97 − = 88
Powered by MathCaptcha

Scroll to Top