PowerShell Hands-on Lab

Let's GO!!

Josh Hendricks

@joshooaj.com

Thanks!

@joshooaj

  • Joshua J Hendricks
    • (call me Josh)
  • Principal Engineer at
    ๐Ÿ”ท Milestone Systems
  • Microsoft MVP
  • Husband, and Dad to...
    • 1 12yo girl
    • 2 cats
    • 4 chickens incl. a broody hen

What We're Doing Today

Speed-running Learn PowerShell in a Month of Lunches

  • โšก Avg ~10 min per topic: intro, demo, questions
  • ๐ŸŽฏ Mental map, not mastery
  • ๐Ÿ“– The book is your companion for going deeper

How This Workshop Works

For Each Topic We'll...

  1. Show some slides: Introduce concepts
  2. Demo it live: Run some sample code
  3. Answer questions: Do some pair programming
  4. Move on: Keep the momentum

๐Ÿ’ฌ Please, ask questions!

There is no better time or place!

Our Agenda

Block Topics Chapters
1 The Shell & Running Commands 1โ€“4
2 Providers & the Pipeline 5โ€“6
3 Modules & Objects 7โ€“9
4 Pipeline Deep Dive, Formatting & Filtering 10โ€“12
5 Remoting, Jobs & ForEach 13โ€“15
6 Variables, I/O & Scripting 16โ€“22
7 Logic, Errors, Debugging & Tips 23โ€“27

Before We Begin

Make sure you have...

Block 1

The Shell & Running Commands

Chapters 1โ€“4

Ch 1. Before You Begin

Why PowerShell?

  • Cross-platform: Windows, macOS, Linux
  • Object-based: not just text, real .NET objects
  • Discoverable: built-in help for everything
  • Extensible: thousands of community modules

Ch 2. Meet PowerShell

Your New Best Friend

$PSVersionTable      # What version am I running?

Get-Location         # Where am I?

Get-Command          # What can I do?

๐Ÿ’ก We'll spend most of our time here today

Ch 3. The Help System

The Most Valuable Skill in PowerShell

Update-Help -ErrorAction SilentlyContinue      # Update your help files first

Get-Help Get-Process                           # Get help on any command
Get-Help Get-Process -Examples
Get-Help Get-Process -Online
  • Get-Help is your first stop for learning any command
  • -Examples shows usage, -Online opens help in your browser

Ch 3. Understanding the Syntax

Get-Process [[-Name] <string[]>] [-ComputerName <string[]>]
Syntax Meaning
[[-Name] Optional, and positional. You don't have to type -Name
<string[]> Parameter type. Accepts one or more strings
[-ComputerName] Optional, named. Not positional, must use the parameter name
No brackets Mandatory

Ch 4. Running Commands

Anatomy of a PowerShell Command

# โ†“ Verb          โ†“ Value   
Get-Process -Name "pwsh" -ErrorAction Stop
#   โ†‘ Noun   โ†‘ Parameter  โ†‘ Common Parameter
  • Verb-Noun naming convention โ€” Get-, Set-, New-, Remove-
  • Parameters modify behavior โ€” use Get-Help to discover them
  • Common parameters like -Verbose, -ErrorAction work everywhere

Ch 4. Aliases & Shortcuts

Get-ChildItem                           # These all do the same thing
dir
ls
gci

Get-Alias ls                            # Find what an alias maps to
Get-Alias -Definition Get-ChildItem     # Find all aliases for a command

๐Ÿ“ Rule of Thumb

Use aliases interactively, not in scripts.

Block 2

Providers & the Pipeline

Chapters 5โ€“6

Ch 5. Working with Providers

PowerShell providers give you a filesystem-like interface to many data stores:

# See all available providers
Get-PSDrive

# Navigate the registry like a filesystem!
Set-Location HKCU:\Software
Get-ChildItem

# Environment variables too
Get-ChildItem Env:

Ch 6. The Pipeline

# Get processes, filter, sort, and display
Get-Process |
    Where-Object CPU -gt 10 |
    Sort-Object CPU -Descending |
    Select-Object -First 5 Name, CPU
  • Each | connects output objects to the next command
  • This is not text processing โ€” it's object processing
  • Easier than text-based pipelines in other shells

Ch 6. Pipeline Exports

Sending Data Somewhere Useful

Get-Process | Export-Csv -Path processes.csv -NoTypeInformation

Get-Service | ConvertTo-Json | Out-File services.json

Get-Process | ConvertTo-Html | Out-File processes.html

Block 3

Modules & Objects

Chapters 7โ€“9

Ch 7. Installing Modules

Find-Module -Name "*Azure*" | Select-Object -First 5 Name, Description

Install-Module -Name Microsoft.PowerShell.SecretManagement -Scope CurrentUser

Get-Command -Module Microsoft.PowerShell.SecretManagement

powershellgallery.com hosts thousands of community modules. It's like npm or pip for PowerShell.

Ch 8. Objects

Everything in PowerShell is an object with properties and methods:

Get-Process | Get-Member           # What kind of object is this?
(Get-Process -Name pwsh).Path      # Access a property
(Get-Date).AddDays(30)             # Call a method
  • Properties = data about the object (Name, Path, CPU)
  • Methods = actions the object can perform (Kill, AddDays)
  • Get-Member is how you discover what's available

Ch 8. Exploring Objects

Select, Sort, Measure

Get-Process | Select-Object Name, CPU, WorkingSet                # Pick specific properties

Get-Service | Sort-Object Status, Name                           # Sort by a property

Get-Process | Measure-Object -Property WorkingSet -Sum -Average  # Count and measure

PowerShell cmdlets return rich objects, not text.

That's why Sort-Object and Select-Object work so well.

Ch 9. A Practical Interlude

The Problem-Solving Pattern

When you face a new task in PowerShell, follow this pattern:

  1. What am I trying to do? Define the goal in plain English
  2. What commands might help? Get-Command *keyword*
  3. How do I use that command? Get-Help Command-Name -Examples
  4. Try it: experiment in the terminal
  5. Refine it: pipe to Where-Object, Sort-Object, Select-Object

โ˜• Break Time

Stretch, grab coffee, ask questions!

Back in 10 minutes

Try some commands on your own!

Block 4

More Pipelines, Formatting & Filtering

Chapters 10โ€“12

Ch 10. The Pipeline 2: Binding

PowerShell binds pipeline input using two strategies:

  • ByValue: matches the entire object by type
  • ByPropertyName: matches properties to parameter names
# Get-Service outputs ServiceController objects,
# Stop-Service accepts ServiceController object ByValue
Get-Service -Name BITS | Stop-Service -WhatIf

# ByPropertyName: CSV columns match parameter names
Import-Csv servers.csv | Test-Connection

Ch 11. Formatting is for Humans

Get-Process | Format-Table Name, CPU, WorkingSet -AutoSize

Get-Process | Format-List *

Get-Process | Format-Wide -Column 4

๐Ÿ“ Rule of Thumb

Format-* commands should be the last thing in your pipeline. Once you format, you can't pipe to anything else useful.

Ch 12. Filtering & Comparisons

Get-Process -Name "pwsh"                         # Filter at the source when you can
Get-Service | Where-Object Status -eq 'Running'  # Use Where-Object when you can't

5 -gt 3                                          # Greater than โ†’ True
"hello" -like "*ell*"                            # Wildcard match โ†’ True
"PowerShell" -match "power"                      # Regex match โ†’ True

๐Ÿ’ก Filter Left, Format Right

Filter as early as possible in the pipeline, format at the end if needed

Block 5

Remoting, Jobs & ForEach

Chapters 13โ€“15

Ch 13. Remote Control

One-to-One and One-to-Many

Enter-PSSession -ComputerName Server01  # Interactive

Invoke-Command -ComputerName Server01, Server02, Server03 -ScriptBlock {
    Get-Service -Name W32Time # Run on multiple machines at once!
}
  • Enter-PSSession โ€” interactive, one-at-a-time
  • Invoke-Command โ€” run on many machines simultaneously
  • Works over WinRM (Windows) or SSH (cross-platform)

Ch 14. Background Jobs

Multitasking in PowerShell

$job = Start-Job -ScriptBlock {
    Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
}
Get-Job                 # Check on it
$job | Receive-Job      # Get the results
  • Start-Job โ†’ run in a separate process
  • Start-ThreadJob โ†’ thread-based (faster, lighter)
  • Invoke-Command -AsJob โ†’ remote commands in background jobs

Ch 15. Working with Many Objects

# Stream services one at a time, memory-friendly
Get-Service | ForEach-Object  { "$($_.Name) is $($_.Status)" }

# Load all services at once, then processes them one at a time
foreach ($svc in Get-Service) { "$($svc.Name) is $($svc.Status)" }

๐Ÿ’ก Which One?

Use ForEach-Object in pipelines. Use foreach in scripts when you don't need streaming.

โ˜• Break Time

Halfway there! Take a breather.

Back in 10 minutes

You're doing great! ๐Ÿš€

Block 6

Variables, I/O & Scripting

Chapters 16โ€“22

Ch 16. Variables

A Place to Store Your Stuff

$name = "PowerShell Summit"           # Simple assignment
$count = 42

$processes = Get-Process              # Store command output

[int]$port = 443                      # Typed variables
[string]$greeting = "Hello, Summit!"
  • PowerShell is dynamically typed โ€” but you can enforce types
  • Store anything: strings, numbers, objects, arrays, hashtables

Ch 16. Strings & Arrays

Quotes, Expansion, and Collections

$who = "World"
"Hello, $who!"    # โ†’ Hello, World! (double-quotes allow variable expansion)
'Hello, $who!'    # โ†’ Hello, $who!  (no variable expansion in single quotes)

$fruits = @("apple", "banana", "cherry")  # Array of fruit
$fruits[0]                                # โ†’ apple
$fruits.Count                             # โ†’ 3

$person = @{ Name = "Josh" }
$person.Name      # โ†’ Josh (Name is a hashtable key, Josh is the value)

Ch 17. Input and Output

Read-Host and the 7 Output Streams

Read-Host "Type anything"          # Gather input as a string (or SecureString)

Write-Output      "This is data"      # Stream 1 - Success stream, goes down pipeline
Write-Error       "Oops..."           # Stream 2 - Defaults to Continue
Write-Warning     "Heads up!"         # Stream 3 - Defaults to Continue
Write-Verbose     "More detail"       # Stream 4 - Defaults to SilentlyContinue
Write-Debug       "Debugging info"    # Stream 5 - Defaults to SilentlyContinue
Write-Information "Extra info"        # Stream 6 - Defaults to SilentlyContinue
Write-Progress    "Working on it"     # Stream 7 - Defaults to Continue

Write-Host        "Only for display"  # Goes to the host only - cannot be captured

Ch 18. Sessions

$session = New-PSSession -ComputerName Server01                     # Create a reusable session

Invoke-Command -Session $session -ScriptBlock { $env:COMPUTERNAME } # Use it multiple times
Invoke-Command -Session $session -ScriptBlock { Get-Process }

Remove-PSSession -Session $session                                  # Clean up

โ„น๏ธ Why Sessions?

Without a session, Invoke-Command creates a new connection. Sessions retain
variables, imported modules, and working directory between calls.

Ch 19. You Call This Scripting?

From commands to scripts

# Save this as Get-DiskReport.ps1
param(
    # A parameter with a default value
    [string]$ComputerName = $env:COMPUTERNAME
)

Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $ComputerName |
    Where-Object { $_.DriveType -eq 3 } |
    Select-Object @{n='Drive';e={$_.DeviceID}},
                  @{n='SizeGB';e={[math]::Round($_.Size/1GB,2)}},
                  @{n='FreeGB';e={[math]::Round($_.FreeSpace/1GB,2)}}

Ch 20. Improving Your Script

function Get-DiskReport {
    [CmdletBinding()]                       # Unlocks `-Verbose`, `-ErrorAction`, and more
    param(
        [Parameter(Mandatory)]              # Forces the user to provide a value
        [ValidateNotNullOrEmpty()]          # Catches bad input early
        [string]$ComputerName
    )

    Write-Verbose "Checking disks on $ComputerName"
    # ... your logic here
}

Ch 21. Regular Expressions

"Server-DC01" -match "DC\d+"      # True: Matches DC followed by one or more digits
$Matches[0]                       # DC01

# Find "ERROR" or "FATAL" in *.log files in the current folder
Select-String -Path *.log -Pattern "ERROR|FATAL"

# Replace with regex
"2026-04-16" -replace "(\d{4})-(\d{2})-(\d{2})", '$2/$3/$1'
# โ†’ 04/16/2026

โœจ Use tools like regex101.com to build and test patterns

Ch 22. Using someone else's script

You will inherit scripts

When reading unfamiliar PowerShell code, look for:

  • param block: what inputs does it expect?
  • process block: where's the main logic?
  • comments: what was the author thinking?
  • Get-Help: does the script have comment-based help?

Block 7

Logic, Errors, Debugging & Tips

Chapters 23โ€“27

Ch 23. Logic and Loops

if / elseif / else

if ($service.Status -eq 'Running') {

    Write-Output 'Service is healthy'

} elseif ($service.Status -eq 'Stopped') {

    Write-Warning 'Service is stopped!'

} else {

    Write-Error "Service is $($service.Status)"

}

foreach & while

foreach ($server in $servers) {

    Test-Connection $server -Count 1 -Quiet

}

$secretNumber = 42
$tries = 0
while ($guess -ne $secretNumber) {
    $tries++
    $guess = Get-Random -Min 1 -Max 100
}
Write-Host "Guessed in $tries tries!"

Ch 24. Handling errors

When Things Go Wrong

try {
    Get-Content foo.txt -EA Stop
} catch {
    Write-Warning "Uh oh: $_"
} finally {
    Write-Verbose "Optional:"
    Write-Verbose "Always runs (usually)"
}
  • -EA Stop turns non-terminating errors into terminating ones
  • try/catch only catches terminating errors
  • $_ in the catch block holds the error details

Ch 25. Debugging

Finding and Fixing Problems

# Add breakpoints
Set-PSBreakpoint .\MyScript.ps1 -Line 10

# Use Write-Debug for investigation
Write-Debug "Variable value: $myVar"

# Debug in VSCode
# Set breakpoints in editor and press F5

๐Ÿ’ก Easiest in VSCode

Set breakpoints with a click in the gutter.

Step through code with F10/F11.

Inspect variables in the debug pane.

Ch 26. Tips, Tricks & Techniques

Power User Moves

# Custom profile startup script
code $PROFILE

# Splatting โ€” clean up long commands
$params = @{
    Path        = "C:\Logs"
    Filter      = "*.log"
    Recurse     = $true
    ErrorAction = "SilentlyContinue"
}
Get-ChildItem @params
# Ternary operator (PowerShell 7+)
$status = $isRunning ? "Running" : "Stopped"

# Syntactic-sugar for...
$status = if ($isRunning) {
    "Running"
} else {
    "Stopped""
}

Ch 26. More Useful Tricks

Operators & String Magic

# Type checking and casting
42 -is [int]            # True
"42" -as [int]          # 42

# String manipulation
"Hello World" -split " "
# @("Hello", "World")

@("one","two") -join ", "    # "one, two"

"Error: disk full" -replace "Error:", "Ope,"
# Array filtering

$numbers = 1..10
$numbers -contains 5           # True
5 -in $numbers                 # True

Ch 27. Never the End

Where to Go From Here

  • ๐Ÿ“– Read the book: Learn PowerShell in a Month of Lunches
  • ๐ŸŒ PowerShell docs: learn.microsoft.com/powershell
  • ๐Ÿ’ฌ Community: Discord, Reddit, PowerShell.org, Bluesky
  • ๐Ÿงช Practice: automate something real at work or home
  • ๐Ÿ“ฆ Explore modules: PowerShell Gallery

Workshop Recap

What We Covered Today

Block What You Learned
1 The shell, help system, running commands
2 Providers and the pipeline
3 Modules, objects, and discovery
4 Pipeline binding, formatting, filtering
Block What You Learned
5 Remoting, jobs, and ForEach
6 Variables, I/O, scripting, regex
7 Logic, errors, debugging, tips & tricks

THANK YOU

Feedback is a gift

Please review this session via the mobile app

Questions? Find me @joshooaj.com

Gotta thank the sponsors!

SPEAKER NOTES: - Walk through each block briefly so people know what's coming - Mention that blocks get progressively more advanced - We'll take 5โ€“10 minute breaks between major blocks

SPEAKER NOTES: - TODO: Update GitHub repo URL - Quick environment check, ask the room if everyone is set up - If not, they can follow along on screen and troubleshoot during break - Point people to the GitHub repo for all materials

SPEAKER NOTES: - Section break, take a breath - This block covers the absolute fundamentals - By the end, everyone should be able to find and run commands

SPEAKER NOTES: - "Life without PowerShell" vs "Life with PowerShell", paint the picture - Emphasize that PowerShell runs everywhere now, not just Windows - This is the "why should I care" slide - PowerShell isn't just for sysadmins anymore. Developers, cloud engineers, security analysts all benefit

SPEAKER NOTES: - DEMO: Open VS Code, show the terminal, run $PSVersionTable - Point out the PowerShell extension features: IntelliSense, integrated terminal - Show that the terminal is a full PowerShell session - This is where we'll spend most of our time. Make sure everyone has it open - Transition: "Now let's learn how to find help when we're stuck"

SPEAKER NOTES: - DEMO: Run Update-Help, then Get-Help Get-Process -Full - Show parameter sets, mandatory vs optional parameters - Show -Examples for practical usage - Emphasize: "If you learn ONE thing today, learn to use Get-Help" - Mention Get-Help about_* topics

SPEAKER NOTES: - Walk through the syntax notation slowly - Square brackets = optional, angle brackets = value type - This is where most beginners get confused โ€” normalize that. It looks intimidating at first; after a few commands it's second nature.

SPEAKER NOTES: - DEMO: Run Get-Process, then with -Name, then with -ErrorAction - Show tab completion for parameter names - Show truncated parameter names (e.g. -N for -Name) - Mention aliases exist but should not be used in scripts

SPEAKER NOTES: - DEMO: Show Get-Alias, explain why ls works in PowerShell - Emphasize: scripts = full names, terminal = aliases are fine - Transition: "We've been using the filesystem. Let's dive deeper."

SPEAKER NOTES: - Short section โ€” two foundational concepts - Providers = how PowerShell sees storage - Pipeline = how commands talk to each other

SPEAKER NOTES: - DEMO: Run Get-PSDrive, navigate to HKCU:\, browse with Get-ChildItem - Show Env: drive โ€” Get-ChildItem Env: - Key insight: same commands (Get-ChildItem, Set-Location) work everywhere - If on Linux/macOS, note that Registry is Windows-only

SPEAKER NOTES: - DEMO: Build this pipeline step by step, adding one pipe at a time - Show what happens at each stage - Emphasize the object nature โ€” properties, not text columns - Mention Export-Csv, Out-File, ConvertTo-Html as pipeline endpoints

SPEAKER NOTES: - DEMO: Export processes to CSV, open the file - Show ConvertTo-Json output - Transition: "We've been using built-in commands. What about adding more?"

SPEAKER NOTES: - This block covers how PowerShell becomes extensible - Modules = packages of commands - Objects = the heart of PowerShell's power

SPEAKER NOTES: - DEMO: Find-Module, Find-Command, Install-Module, Get-Command -Module - Mention -Scope CurrentUser to avoid admin requirements on Windows PowerShell - Show a fun module if time allows - Key point: you don't have to write everything yourself

SPEAKER NOTES: - DEMO: Get-Process | Get-Member โ€” walk through the output - Show properties vs methods - Access a property with dot notation - This is THE concept that separates PowerShell from other shells

SPEAKER NOTES: - DEMO: Build up from Get-Process to Select, Sort, Measure - Show that Select-Object limits which properties pass through - Transition: "Let's put this into practice with a quick challenge"

SPEAKER NOTES: - DEMO: Walk through a real example: "Find all services that are stopped and could be started" 1. Get-Command *service* 2. Get-Help Get-Service -Examples 3. Get-Service | Where-Object Status -eq Stopped - Even experienced PowerShell users follow these same steps โ€” you never memorize everything, you learn how to discover - Transition: "Time for a break! Stretch, grab coffee, try some commands."

SPEAKER NOTES: - Now we go deeper on things we've already touched - Pipeline binding, formatting, and filtering - These are the skills that make you productive day-to-day

SPEAKER NOTES: - TODO: Write Trace-Command example - DEMO: Show Trace-Command to visualize ByValue vs ByPropertyName - Show what happens when things DON'T match - Use Select-Object with calculated properties to reshape: @{n='ComputerName'; e={$_.ServerName}} - This is dense โ€” it's OK to just understand the concept

SPEAKER NOTES: - DEMO: Show Format-Table vs Format-List vs Format-Wide - Show what happens when you pipe Format-Table to Export-Csv (broken!) - Key rule: Format-* goes at the END, always

SPEAKER NOTES: - DEMO: Show filtering with both source parameter and Where-Object - Show common comparison operators: -eq, -ne, -gt, -lt, -like, -match - Emphasize "filter left" โ€” performance matters - Transition: "Next up โ€” remoting! Doing things on other machines."

SPEAKER NOTES: - This is where PowerShell starts to feel like a superpower - Run commands on remote machines - Run things in the background - Process many objects at once

SPEAKER NOTES: - DEMO: If possible, show Enter-PSSession to localhost - Show Invoke-Command with -ComputerName - Explain that remoting needs to be enabled and configured - Mention SSH-based remoting for cross-platform scenarios

SPEAKER NOTES: - DEMO: Start a job, check status, receive results - Mention Start-ThreadJob as the modern, faster alternative - Jobs are great for long-running tasks you don't want to wait for

SPEAKER NOTES: - DEMO: Show both styles side by side - Mention ForEach-Object -Parallel for PowerShell 7+ - Key: if a cmdlet accepts arrays natively, use that instead of looping - Transition: "Break time! Then we start scripting."

SPEAKER NOTES: - Biggest block โ€” covers a lot of ground - We transition from "running commands" to "writing scripts" - Variables, input/output, reusable code, regex

SPEAKER NOTES: - DEMO: Create variables, show types with .GetType() - Reference variables with $ - Show storing command output in a variable - Show array access: $processes[0], $processes.Count - Keep it simple โ€” don't go deep on types

SPEAKER NOTES: - DEMO: Show string expansion, single vs double quotes - Show array creation and indexing - Show hashtable creation and access - These are the building blocks for scripts

SPEAKER NOTES: - DEMO: Show the difference between Write-Output and Write-Host - Pipe Write-Output to a variable vs Write-Host (nothing captured!) - Mention Read-Host exists but is bad practice in scripts

SPEAKER NOTES: - DEMO: Create a session, run multiple commands, show state persists - Mention implicit remoting (Import-PSSession) if time allows - This is a brief topic โ€” move through it quickly

SPEAKER NOTES: - DEMO: Create a .ps1 file, run it, pass a parameter - Show that it's literally the same commands we type interactively - The param block is the only new concept here

SPEAKER NOTES: - DEMO: Add CmdletBinding and Mandatory to a simple script - Show -Verbose output appearing - Show what happens when you don't provide a mandatory param - Key: a few attributes make your script behave like a real cmdlet

SPEAKER NOTES: - DEMO: Show a simple -match, access $Matches - Show Select-String on a log file - Don't go deep on regex syntax โ€” just show it exists - Regex is a skill you build over time, not in 5 minutes

SPEAKER NOTES: - DEMO: Open a script from the repo, walk through how to read it - param block first โ†’ understand the inputs and how to call the script - process block โ†’ that's where the main logic lives; look for it in longer scripts - comments โ†’ read them first, they tell you what the author was thinking - Get-Help โ†’ well-written scripts have comment-based help; try Get-Help .\script.ps1 - You'll spend more time reading code than writing it โ€” get comfortable with this process - Transition: "Last couple blocks โ€” logic, errors, and wrapping up!"

SPEAKER NOTES: - Home stretch! We're covering scripting mechanics now - Loops, error handling, debugging, and tips - These make the difference between "a script" and "a good script"

SPEAKER NOTES: - DEMO: Show a simple if/else, then a foreach loop - Mention switch statement exists but don't demo - Remind people: prefer pipeline over explicit loops when possible

SPEAKER NOTES: - DEMO: Show try/catch with and without -ErrorAction Stop - Explain terminating vs non-terminating errors - Show $_ and $_.Exception.Message - This is critical for reliable scripts

SPEAKER NOTES: - DEMO: Set a breakpoint in VS Code, run script, step through - Show the Variables pane, Watch expressions - Mention Write-Debug and -Debug switch - VS Code debugging is the way to go for anything non-trivial

SPEAKER NOTES: - DEMO: Show $PROFILE, create a simple profile greeting - Show splatting with a real command - Mention other operators: -replace, -split, -join, -contains, -in - These are quality-of-life improvements that add up

SPEAKER NOTES: - Quick overview โ€” don't dwell on each one - Point people to Get-Help about_Operators for the full list - These come up constantly in real scripts

SPEAKER NOTES: - Encourage people to pick ONE thing to automate when they get back - Mention the PowerShell community is incredibly welcoming - Point to the GitHub repo for all session materials - The best way to learn: use it โ€” find a repetitive task, automate it, break it, fix it. That's how every expert started.

SPEAKER NOTES: - Use this as a victory lap โ€” you just speed-ran an entire book - Pause and let it sink in: this is genuinely a lot of ground to cover - Invite any final questions before the wrap-up - Remind people: you won't remember all of this, and that's OK โ€” you know it exists and you know how to find it again

SPEAKER NOTES: - Thank everyone for spending 4 hours with you - Point to session review in the app - Offer to chat in the hallway track - Share GitHub repo link one more time