Windows
PowerShell Basics for Admins¶
PowerShell is the automation and configuration shell built into Windows Server. Unlike a traditional text shell, it passes objects through the pipeline, which makes it far more reliable for administration than parsing screen output.
Tested on
Windows Server 2022 with Windows PowerShell 5.1 (preinstalled). The same cmdlets work in PowerShell 7.x (the cross-platform successor, installed separately) unless noted. Cross-platform PowerShell 7 also runs on Linux.
What is PowerShell, and why does it matter?¶
PowerShell is two things at once: an interactive command shell and a scripting
language. The thing that sets it apart from cmd.exe or a Unix shell is that the
pipeline carries .NET objects, not text.
In a text shell you run a command, get a block of text, then chop it up with tools
like grep, awk, and cut - and your script breaks the moment the output format
changes. In PowerShell, Get-Process hands the next command real objects with
named properties (Name, Id, CPU, WorkingSet), so you select and filter on
properties, never on column positions.
# Objects in the pipeline: filter on a real property, no text parsing
Get-Process | Where-Object CPU -gt 100 | Select-Object Name, Id, CPU
This is why PowerShell is the backbone of Windows automation - the same skills apply whether you manage Active Directory, IIS, or file shares.
Cmdlets: the Verb-Noun naming model¶
The native commands in PowerShell are cmdlets (pronounced "command-lets"), and they follow a strict Verb-Noun convention:
| Cmdlet | Verb | Noun | Does |
|---|---|---|---|
Get-Service |
Get | Service | Reads services |
Stop-Service |
Stop | Service | Stops a service |
New-Item |
New | Item | Creates a file/folder |
Set-Location |
Set | Location | Changes directory |
Approved verbs are standardized (Get, Set, New, Remove, Start, Stop,
Restart, Add, ...). Once you learn the pattern you can often guess a cmdlet
name. See the full list with Get-Verb.
Aliases for muscle memory
Many cmdlets have short aliases, including some that mirror cmd/Unix:
ls/dir -> Get-ChildItem, cd -> Set-Location, cat -> Get-Content,
ps -> Get-Process. Use them interactively, but write full cmdlet names in
scripts for readability.
The pipeline passes objects (not text)¶
The pipe character | sends the output objects of one cmdlet as input
objects to the next. Because the objects keep their structure, downstream
cmdlets bind to properties by name.
# Stop every service whose name starts with "Print", confirming each
Get-Service -Name 'Print*' | Stop-Service -WhatIf
-WhatIf previews what would happen without doing it - a habit worth keeping for
any destructive command.
Discovery: find and learn cmdlets¶
You never need to memorize everything. Three cmdlets let you explore:
# Find cmdlets - by verb, noun, or wildcard
Get-Command -Verb Get -Noun Service
Get-Command *event*
# Read help (add -Examples or -Full); -Online opens the web docs
Get-Help Get-Service -Examples
Update-Help # download the latest help text once
# Inspect the OBJECT a cmdlet returns - its properties and methods
Get-Service | Get-Member
Get-Member is the most underrated tool: it tells you exactly which properties you
can Select-Object or Where-Object on, because it shows the object's real shape.
Common cmdlets every admin uses¶
# Services and processes
Get-Service -Name Spooler
Get-Process -Name explorer
# Files and folders (the filesystem is a "provider")
Get-ChildItem C:\Logs -Recurse -Filter *.log
Set-Location C:\Logs
# The event logs - prefer the modern Get-WinEvent
Get-WinEvent -LogName System -MaxEvents 20
Get-WinEvent -FilterHashtable @{ LogName = 'System'; Level = 2 } -MaxEvents 50
# Get-EventLog is the older, classic-log-only cmdlet (still works on 2022)
Get-EventLog -LogName System -Newest 20
Get-WinEvent vs Get-EventLog
Get-EventLog only reads the classic logs (Application, System, Security).
Get-WinEvent reads all logs, including the newer "Applications and
Services" logs, and is much faster with server-side filtering via
-FilterHashtable. Use Get-WinEvent for new work.
Filtering, selecting, sorting, formatting¶
These four cmdlets cover most day-to-day data shaping:
# Where-Object: keep only matching objects
Get-Service | Where-Object Status -eq 'Running'
# Select-Object: pick properties (or the first/last N)
Get-Process | Select-Object Name, Id, WorkingSet -First 5
# Sort-Object: order by a property
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5
# Format-Table / Format-List: presentation ONLY, always last in the pipe
Get-Service | Where-Object Status -eq 'Running' | Format-Table Name, DisplayName -AutoSize
Format-* breaks the pipeline
Format-Table and Format-List produce formatting objects, not data. Put
them at the end of a pipeline only. Never pipe their output into
Where-Object, Export-Csv, etc. - you will lose the real objects. Use
Export-Csv / ConvertTo-Json before any Format-*.
Comparison operators are words, not symbols: -eq, -ne, -gt, -lt, -ge,
-le, -like (wildcards), -match (regex), -contains.
Variables and basic scripting¶
Variables start with $. PowerShell is loosely typed but you can pin a type.
if / foreach¶
$svc = Get-Service -Name Spooler
if ($svc.Status -eq 'Running') {
Write-Output "$($svc.Name) is up"
} else {
Start-Service $svc.Name
}
# Loop over a collection of objects
foreach ($s in Get-Service | Where-Object Status -eq 'Stopped') {
Write-Output "Stopped: $($s.Name)"
}
Save scripts as .ps1 files and run them with .\script.ps1. Comment lines start
with #; block comments use <# ... #>.
Execution policy¶
By default Windows Server may refuse to run scripts. The execution policy is a safety setting (not a security boundary) that controls which scripts can run.
# See the current policy
Get-ExecutionPolicy -List
# Allow local scripts; downloaded scripts must be signed (sensible default)
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Run PowerShell as Administrator to set a machine-wide (LocalMachine) scope.
RemoteSigned is the common, balanced choice; avoid Unrestricted/Bypass except
for short, deliberate troubleshooting.
Remoting: run commands on other servers¶
PowerShell Remoting (over WS-Management / WinRM) lets you manage servers without
RDP. On most Windows Server installs WinRM is already enabled; if not, run
Enable-PSRemoting -Force on the target.
# Interactive session ON a remote server (like SSH-ing in)
Enter-PSSession -ComputerName SERVER01 -Credential CORP\admin
# ... run cmdlets as if local ...
Exit-PSSession
# One-off command on one or many servers (runs in parallel)
Invoke-Command -ComputerName SERVER01, SERVER02 -ScriptBlock {
Get-Service -Name Spooler
}
# Reusable session for several commands
$s = New-PSSession -ComputerName SERVER01
Invoke-Command -Session $s -ScriptBlock { Get-Process }
Remove-PSSession $s
Invoke-Command returns real objects from each machine, tagged with a
PSComputerName property so you know which server each result came from.
PowerShell vs Bash¶
If you also work on Linux, the mental model is different. See the Linux Bash scripting page for the other side.
| Concept | PowerShell | Bash |
|---|---|---|
| Pipeline carries | Objects (.NET) with properties | Text (byte streams) |
| Filtering | Where-Object Status -eq 'Running' |
grep, awk, cut on text |
| Selecting fields | Select-Object Name, Id (by property) |
awk '{print $1}' (by column) |
| Command naming | Verb-Noun (Get-Service) |
freeform (systemctl, ls) |
| Variables | $x = 'v' |
x=v (no spaces) |
| Comparison | -eq, -gt, -like |
-eq/==, -gt, [[ ... ]] |
| Elevation | Run shell as Administrator | sudo per command |
| Remote exec | Invoke-Command (WinRM) |
ssh host 'cmd' |
| Help | Get-Help, Get-Member |
man, --help |
The big takeaway: in Bash you parse text; in PowerShell you query objects.
Verify your work¶
- Run
Get-Command -Verb Get -Noun Serviceand confirmGet-Serviceis listed. - Run
Get-Service | Get-Memberand confirm you can see aStatusproperty. - Run
Get-Service | Where-Object Status -eq 'Running' | Select-Object -First 3and confirm only running services are returned with the columns you asked for. - Run
Get-ExecutionPolicy -Listand confirmCurrentUsershowsRemoteSignedafter setting it. - If you have a second server, run
Invoke-Command -ComputerName SERVER01 -ScriptBlock { hostname }and confirm it returns that server's name.
Summary¶
- PowerShell is a shell and a scripting language whose pipeline carries objects, so you filter on properties instead of parsing text.
- Cmdlets follow Verb-Noun naming; discover them with
Get-Command,Get-Help, andGet-Member. - Everyday cmdlets:
Get-Service,Get-Process,Get-ChildItem,Set-Location,Get-WinEvent(prefer overGet-EventLog). - Shape data with
Where-Object,Select-Object,Sort-Object, and (last only)Format-Table/Format-List. - Use
$variables,if/foreach, setSet-ExecutionPolicy RemoteSigned, and manage remote servers withEnter-PSSessionandInvoke-Command. - Versus Bash: objects vs text is the key difference. These basics power the rest of the Windows Server track.