PowerShell console window showing cmdlet output

PowerShell Basics for Sysadmins: From Zero to Scripting

“Can you script?”

That question separates junior admins from senior ones. And in the Windows world, the answer needs to be PowerShell. It’s not optional anymore – Server Core has no GUI, Azure is PowerShell-native, and anything at scale requires automation.

The good news? PowerShell is learnable. If you’ve used any command line, you’re halfway there. This guide gets you from zero to productive.

What you’ll learn:

  • Why PowerShell (not just cmd)
  • Cmdlet structure and discovery
  • The pipeline – PowerShell’s superpower
  • Variables, loops, and conditionals
  • Your first useful scripts

Career Value: PowerShell scripting is the single skill that transforms admins from button-clickers to automation engineers. It’s the difference between a GBP 35k helpdesk role and a GBP 55k+ DevOps position. Every serious Windows job listing asks for it.

Quick Reference

Cmdlet Purpose Example
Get-Help Documentation Get-Help Get-Process -Full
Get-Command Find cmdlets Get-Command *service*
Get-Member See object properties Get-Process | Get-Member
Select-Object Choose properties Get-Process | Select Name, CPU
Where-Object Filter results Get-Process | Where CPU -gt 10
ForEach-Object Loop through items 1..10 | ForEach { $_ * 2 }

Why PowerShell?

CMD is Dead (Mostly)

CMD PowerShell
Text-based output Object-based output
Limited scripting Full programming language
Windows only Cross-platform (PowerShell 7)
No remoting built-in Native remoting
Dying The future

Real Example: Finding Large Files

CMD:

forfiles /S /M * /C "cmd /c if @fsize GEQ 104857600 echo @path @fsize"

PowerShell:

Get-ChildItem -Recurse | Where-Object { $_.Length -gt 100MB } | Select-Object FullName, Length

PowerShell is readable. That matters when you’re troubleshooting at 2am.

The Verb-Noun Structure

Every PowerShell cmdlet follows the pattern: Verb-Noun

Common Verbs:

  • Get – Retrieve information
  • Set – Change something
  • New – Create something
  • Remove – Delete something
  • Start / Stop – Control services/processes
  • Enable / Disable – Toggle features

Examples:

Get-Process      # Get running processes
Set-Location     # Change directory (cd)
New-Item         # Create file/folder
Remove-Item      # Delete file/folder
Start-Service    # Start a service
Stop-Service     # Stop a service

Pro Tip: If you can guess the verb and noun, you can often guess the cmdlet. Need to get services? Try Get-Service. Need to create a user? Try New-ADUser.

Finding Commands

Get-Command: Your Discovery Tool

# Find all commands with "service" in the name
Get-Command *service*

# Find all commands in a module
Get-Command -Module ActiveDirectory

# Find commands by verb
Get-Command -Verb Get

# Find commands that work with processes
Get-Command -Noun Process

Get-Help: Built-in Documentation

# Basic help
Get-Help Get-Process

# Full help with examples
Get-Help Get-Process -Full

# Just the examples
Get-Help Get-Process -Examples

# Online help (opens browser)
Get-Help Get-Process -Online

First time? Update help:

Update-Help -Force

The Pipeline: PowerShell’s Superpower

The pipeline (|) passes objects from one command to the next. This is what makes PowerShell powerful.

Basic Pipeline

# Get processes, sort by CPU, show top 10
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10

# Get services, filter to stopped, format as table
Get-Service | Where-Object Status -eq 'Stopped' | Format-Table Name, Status

Understanding Objects

PowerShell passes objects, not text. This is crucial.

# See what properties an object has
Get-Process | Get-Member

# A process object has: Name, CPU, Memory, Id, etc.
# You can access any of these
Get-Process | Select-Object Name, CPU, WorkingSet

Filtering with Where-Object

# Services that are running
Get-Service | Where-Object { $_.Status -eq 'Running' }

# Shorthand (PowerShell 3+)
Get-Service | Where Status -eq 'Running'

# Multiple conditions
Get-Process | Where-Object { $_.CPU -gt 10 -and $_.WorkingSet -gt 100MB }

Selecting Properties

# Choose specific properties
Get-ADUser -Filter * -Properties EmailAddress | Select-Object Name, EmailAddress, Enabled

# Create calculated properties
Get-Process | Select-Object Name, @{Name='MemoryMB';Expression={$_.WorkingSet/1MB}}

Variables and Data Types

Basic Variables

# Assign a variable
$name = "John"
$number = 42
$servers = @("DC01", "DC02", "WEB01")

# Use a variable
Write-Output "Hello, $name"
Write-Output "The answer is $number"

Arrays

# Create an array
$servers = @("DC01", "DC02", "WEB01")

# Access elements
$servers[0]    # DC01
$servers[-1]   # WEB01 (last item)

# Loop through
foreach ($server in $servers) {
    Write-Output "Processing $server"
}

Hash Tables

# Create a hash table
$user = @{
    Name = "John Smith"
    Department = "IT"
    Title = "Sysadmin"
}

# Access values
$user.Name
$user["Department"]

Control Flow

If/Else

$service = Get-Service -Name "Spooler"

if ($service.Status -eq "Running") {
    Write-Output "Print spooler is running"
} elseif ($service.Status -eq "Stopped") {
    Write-Output "Print spooler is stopped"
    Start-Service -Name "Spooler"
} else {
    Write-Output "Unknown status: $($service.Status)"
}

ForEach Loop

$servers = @("DC01", "DC02", "WEB01")

foreach ($server in $servers) {
    $result = Test-Connection -ComputerName $server -Count 1 -Quiet
    if ($result) {
        Write-Output "$server is online"
    } else {
        Write-Output "$server is OFFLINE"
    }
}

ForEach-Object (Pipeline)

# Same thing, pipeline style
@("DC01", "DC02", "WEB01") | ForEach-Object {
    $online = Test-Connection -ComputerName $_ -Count 1 -Quiet
    [PSCustomObject]@{
        Server = $_
        Online = $online
    }
}

Practical Scripts

Script 1: Find Large Files

# Find files over 100MB, export to CSV
$path = "C:\Users"
$minSize = 100MB

Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt $minSize } |
    Select-Object FullName, @{N='SizeMB';E={[math]::Round($_.Length/1MB,2)}}, LastWriteTime |
    Sort-Object SizeMB -Descending |
    Export-Csv -Path "C:\Temp\LargeFiles.csv" -NoTypeInformation

Write-Output "Report saved to C:\Temp\LargeFiles.csv"

Script 2: Check Service Status Across Servers

$servers = @("DC01", "DC02", "WEB01")
$serviceName = "Spooler"

# Get-Service -ComputerName only exists in Windows PowerShell 5.1; PowerShell 7 removed it.
# Invoke-Command (WinRM remoting, enabled by default on Windows Server) works in both.
$results = foreach ($server in $servers) {
    try {
        $status = Invoke-Command -ComputerName $server -ErrorAction Stop -ScriptBlock {
            (Get-Service -Name $using:serviceName -ErrorAction Stop).Status.ToString()
        }
        [PSCustomObject]@{
            Server = $server
            Service = $serviceName
            Status = $status
        }
    } catch {
        [PSCustomObject]@{
            Server = $server
            Service = $serviceName
            Status = "ERROR: $($_.Exception.Message)"
        }
    }
}

$results | Format-Table -AutoSize

Script 3: Bulk User Creation

# CSV file with: FirstName,LastName,Department
$users = Import-Csv -Path "C:\Temp\NewUsers.csv"
# Prompt for the initial password rather than hardcoding one in the script
$initialPassword = Read-Host -AsSecureString "Initial password"

foreach ($user in $users) {
    $username = "$($user.FirstName.Substring(0,1))$($user.LastName)".ToLower()

    New-ADUser -Name "$($user.FirstName) $($user.LastName)" `
        -GivenName $user.FirstName `
        -Surname $user.LastName `
        -SamAccountName $username `
        -UserPrincipalName "[email protected]" `
        -Department $user.Department `
        -Path "OU=Users,DC=corp,DC=example,DC=com" `
        -AccountPassword $initialPassword `
        -Enabled $true `
        -ChangePasswordAtLogon $true

    Write-Output "Created user: $username"
}

PowerShell vs Bash: Quick Comparison

Task Bash PowerShell
List files ls -la Get-ChildItem
Find text in files grep "text" file Select-String "text" file
Process list ps aux Get-Process
Current directory pwd Get-Location
Environment variable echo $PATH $env:PATH
Loop for i in 1 2 3; do echo $i; done 1..3 | ForEach { $_ }

Pro Tip: PowerShell has aliases for common Bash/CMD commands. ls, cd, pwd, cat all work – but they’re calling PowerShell cmdlets underneath.

Interview Questions

Q1: “What’s the difference between ForEach-Object and foreach?”

Good Answer: “foreach is a language statement – it loads all items into memory first, then iterates. ForEach-Object is a cmdlet used in the pipeline – it processes items one at a time as they flow through. For large datasets, ForEach-Object is more memory-efficient. For speed with smaller sets, foreach is faster.”

Q2: “How do you find out what a cmdlet does and what parameters it has?”

Good Answer: “Get-Help CmdletName -Full shows complete documentation including parameters and examples. Get-Command CmdletName shows the syntax. Get-Member piped after a cmdlet shows the properties and methods of the output objects. I usually start with Get-Help -Examples to see practical usage.”

Q3: “Write a one-liner to find all stopped services and start them.”

Good Answer:

Get-Service | Where Status -eq 'Stopped' | Start-Service

“Though in practice, I’d add -WhatIf first to preview, and probably filter to specific services rather than starting everything.”

Career Application

On your resume:

  • “Automated user provisioning with PowerShell, reducing onboarding time by 80%”
  • “Developed PowerShell scripts for server health monitoring across 50+ servers”
  • “Created bulk AD management scripts for user lifecycle management”

Demonstrate:

  • Object pipeline understanding
  • Error handling (try/catch)
  • Real scripts you’ve written
  • Ability to read and modify existing scripts

Next Steps

Scripting is what separates admins from senior admins. Next up: Group Policy – controlling hundreds of machines with a few clicks.

Windows Fundamentals Series

Part 3 of 6

Previous: Active Directory Essentials | Next: Group Policy Deep Dive

Frequently Asked Questions

Why should sysadmins learn PowerShell?

PowerShell is the primary management tool for Windows Server, Active Directory, Exchange, Azure, and Microsoft 365. CMD cannot manage modern Microsoft services. PowerShell’s object-oriented pipeline, remote management capabilities, and integration with .NET make it essential for automating Windows administration tasks at scale.

What is the PowerShell pipeline and why is it powerful?

The PowerShell pipeline passes objects (not text) between commands using the | symbol. Each command receives structured objects with properties and methods, not raw strings. This means you can filter, sort, select, and transform data without text parsing. For example, Get-Process | Where-Object CPU -gt 100 | Sort-Object CPU filters and sorts process objects directly.

How do I find PowerShell commands I need?

Use Get-Command with wildcards: Get-Command *user* finds all commands related to users. Use Get-Help for documentation: Get-Help Get-ADUser -Examples shows usage examples. All PowerShell commands follow a Verb-Noun naming convention (Get-Process, Set-Item, New-ADUser) which makes discovery intuitive once you learn the pattern.

What is the difference between PowerShell and CMD?

CMD is a legacy text-based command interpreter with limited scripting. PowerShell is a modern object-oriented shell and scripting language built on .NET. PowerShell handles complex data types, remote management, module imports, error handling, and integrates with APIs. CMD is still useful for quick one-liners but PowerShell replaces it for all serious administration.

Can I use PowerShell on Linux?

Yes. PowerShell 7 (the successor to PowerShell Core 6) runs on Linux, macOS, and Windows. Install via your package manager (apt, yum) or the official Microsoft repository. While Linux-native tools (bash, awk, sed) are typically preferred on Linux, cross-platform PowerShell is useful for managing Azure, Microsoft 365, and hybrid environments from a Linux workstation.

Enjoyed this guide?

New articles on Linux, homelab, cloud, and automation every 2 days. No spam, unsubscribe anytime.

Scroll to Top