> ## Content Index
> Fetch the complete content index at: https://blog.sudowl.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# PowerShell for Sysadmins — A Cheatsheet From My Daily Use
- URL: https://blog.sudowl.com/powershell-sysadmin-cheatsheet/
- Published: 2026-04-19T14:00:00.000Z
- Updated: 2026-10-11T08:34:30.000Z
- Description: The PowerShell snippets I actually use every day on Windows Server — pipeline filters, remoting, services, event logs, scheduled tasks, error handling.
- Author: Lukas
- Tags: Windows Server

I script PowerShell daily, mostly on Windows Server boxes. This is the snippets I keep typing, organized so I can find them when I'm tired.

Not a tutorial. Reference. If you've never written PowerShell, start with [How I use Claude to write PowerShell scripts](/how-i-use-claude-powershell-scripts/) — that post covers the workflow, this one is the language.

## Pipeline patterns

PowerShell pipes objects, not text. The patterns:

```powershell
# Filter
Get-Service | Where-Object { $_.Status -eq 'Stopped' }

# Project (select fields)
Get-Process | Select-Object Name, CPU, WorkingSet -First 10

# Sort
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5

# Group
Get-ChildItem -Recurse | Group-Object Extension | Sort-Object Count -Descending

# ForEach
Get-ChildItem *.log | ForEach-Object { Compress-Archive $_ "$($_.Name).zip" }

```

`Where-Object` and `ForEach-Object` have aliases `?` and `%`. Don't use them in scripts (unreadable), do use them at the prompt.

## Service management

```powershell
# State
Get-Service -Name spooler
Get-Service | Where-Object Status -eq Running

# Lifecycle
Start-Service spooler
Stop-Service spooler -Force
Restart-Service spooler

# Startup type
Set-Service spooler -StartupType Disabled
Set-Service spooler -StartupType Automatic

```

For services that don't appear in `Get-Service` (or to manage cross-machine), `sc.exe` and `Get-CimInstance Win32_Service` are the alternatives.

## Files and paths

```powershell
# Find recent
Get-ChildItem C:\Logs -Recurse -Filter *.log |
  Where-Object LastWriteTime -gt (Get-Date).AddDays(-7)

# Big files
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
  Sort-Object Length -Descending |
  Select-Object FullName, Length -First 20

# Delete old files
Get-ChildItem C:\Backup -Filter *.bak |
  Where-Object LastWriteTime -lt (Get-Date).AddDays(-30) |
  Remove-Item -Force

```

`-ErrorAction SilentlyContinue` swallows access-denied noise on system folders. Don't use it elsewhere — it hides real errors.

## Event logs

```powershell
# Recent failed logons
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4625} -MaxEvents 20

# Unexpected shutdowns
Get-WinEvent -FilterHashtable @{LogName='System'; ID=6008} -MaxEvents 5

# Errors in last hour, all logs
Get-WinEvent -FilterHashtable @{
  LogName='Application','System'
  Level=1,2,3
  StartTime=(Get-Date).AddHours(-1)
}

```

`-FilterHashtable` is fast (server-side filter). `Get-WinEvent | Where-Object` is slow (all events come back, then filter). Always filter at source for big logs.

Useful for hunting after [RDP brute-force attempts](/rdp-hardening-windows-server-nla-firewall/) or auditing post-incident.

## Networking

```powershell
# Listening ports
Get-NetTCPConnection -State Listen | Select LocalAddress, LocalPort, OwningProcess

# Process owning a port
Get-NetTCPConnection -LocalPort 443 |
  ForEach-Object { Get-Process -Id $_.OwningProcess }

# Test connectivity (replaces ping + telnet for ports)
Test-NetConnection google.com -Port 443
Test-Connection 8.8.8.8 -Count 4

# DNS lookup
Resolve-DnsName example.com -Type A
Resolve-DnsName example.com -Server 1.1.1.1

```

`Test-NetConnection` is slow. For quick port checks, `tnc -ComputerName x -Port y -InformationLevel Quiet` returns just `True/False`.

## Remoting

```powershell
# One-shot command
Invoke-Command -ComputerName server01 -ScriptBlock { Get-Service spooler }

# Persistent session
$s = New-PSSession -ComputerName server01
Invoke-Command -Session $s -ScriptBlock { ... }
Enter-PSSession $s    # interactive
Remove-PSSession $s

# Multiple servers, parallel
Invoke-Command -ComputerName srv01, srv02, srv03 -ScriptBlock {
  Get-Service | Where-Object Status -eq Stopped
}

```

WinRM has to be enabled on the target (`Enable-PSRemoting -Force`). Cross-domain or workgroup needs `TrustedHosts` set on the client.

## Scheduled tasks

```powershell
# List
Get-ScheduledTask | Where-Object State -ne Disabled

# Create one
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
  -Argument '-File C:\Scripts\backup.ps1'
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
Register-ScheduledTask -TaskName 'Nightly Backup' `
  -Action $action -Trigger $trigger -RunLevel Highest -User SYSTEM

# Run now
Start-ScheduledTask -TaskName 'Nightly Backup'

# Delete
Unregister-ScheduledTask -TaskName 'Nightly Backup' -Confirm:$false

```

Scheduled tasks are the cron equivalent. SYSTEM-account tasks don't have a desktop or network drives — UNC paths and explicit credentials only.

## User and account management

```powershell
# Local users
Get-LocalUser
New-LocalUser -Name svc-app -NoPassword -AccountNeverExpires
Set-LocalUser -Name svc-app -Password (ConvertTo-SecureString 'X' -AsPlainText -Force)
Add-LocalGroupMember -Group Administrators -Member svc-app

# AD users (RSAT installed)
Get-ADUser -Filter "Enabled -eq 'true'" -Properties LastLogonDate
New-ADUser -Name "Jane Doe" -SamAccountName jdoe -Enabled $true `
  -AccountPassword (Read-Host -AsSecureString)

```

Built-in `Administrator` rename pattern from [RDP hardening](/rdp-hardening-windows-server-nla-firewall/) — `Rename-LocalUser`.

For [creating Windows users from cmd](/create-windows-user-cmd-net-user/), `net user` still works and is shorter for one-off creates.

## Error handling

```powershell
try {
    Get-Item C:\does-not-exist -ErrorAction Stop
} catch {
    Write-Error "File not found: $_"
} finally {
    # cleanup
}

```

`-ErrorAction Stop` is mandatory for `try/catch` to fire on cmdlet errors. Without it, cmdlet errors are non-terminating and skip the catch block.

For scripts:

```powershell
$ErrorActionPreference = 'Stop'   # at top of script
Set-StrictMode -Version Latest    # surfaces typos as errors

```

These two lines turn PowerShell from forgiving to actually-tells-you-when-it-broke. Use them in every script.

## Useful one-liners

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

# Top 10 processes by RAM
Get-Process | Sort-Object WorkingSet -Descending |
  Select Name, @{n='RAM_MB';e={[math]::Round($_.WorkingSet/1MB,1)}} -First 10

# Last 5 reboots
Get-WinEvent -FilterHashtable @{LogName='System'; ID=6005} -MaxEvents 5 |
  Select TimeCreated, Message

# WHOIS-equivalent for IPs (uses RIPE)
Invoke-RestMethod "https://stat.ripe.net/data/whois/data.json?resource=8.8.8.8"

```

## Tips that took me too long to learn

- **`Get-Member` on anything.** Don't memorize properties — pipe to `Get-Member` and read.
- **Tab-completion expands.** Type `Get-Wi`+Tab → `Get-WinEvent`. Type a parameter `-` then Tab to cycle parameters.
- **`-WhatIf` before destructive commands.** `Remove-Item -Recurse -WhatIf` shows what would happen. Add it, read output, remove it, run for real.
- **PowerShell 7 ≠ Windows PowerShell 5.1.** New cmdlets work on 7, not 5.1\. On Server, you usually have 5.1 — install 7 explicitly if you need it (`winget install Microsoft.PowerShell`).
- **The pipeline streams.** `Get-ChildItem -Recurse` doesn't materialize everything before the next stage runs. Filter early to keep memory low.

## When scripting gets bigger

Scripts longer than \~50 lines benefit from being a module (`.psm1`) with discrete functions. Each function does one thing, has comment-based help, gets unit-tested with Pester. The transition is the same one as bash → Python — pragmatic, not theoretical.

For longer projects I lean on Claude — see [the pattern in the workflow post](/how-i-use-claude-powershell-scripts/). The cheatsheet here is the layer underneath: knowing the language so you can read and verify what gets generated.

---

### Related posts

- [Reset a Forgotten Windows Administrator Password — the Utilman Trick](https://blog.diengdoh.com/reset-forgotten-windows-admin-password-utilman/?ref=blog.sudowl.com)
- [Windows Server Initial Setup Checklist (2026 Edition)](https://blog.diengdoh.com/windows-server-initial-setup-checklist/?ref=blog.sudowl.com)
- [Enable Remote Desktop (RDP) on Windows Server — CMD & PowerShell](https://blog.diengdoh.com/enable-rdp-windows-server-powershell-cmd/?ref=blog.sudowl.com)