L10. Capstone: Build a Safe Admin Inventory Runbook
Combine the course into a practical runbook that collects system inventory, exports CSV and JSON, handles errors, supports -WhatIf, logs progress, and can run on a schedule.
Project Goal
You will build a safe inventory runbook that collects host, process, service, and disk data. The point is not to gather every possible field. The point is to write automation that is predictable, readable, and safe to run repeatedly.
Requirements
Your script should:
- Accept an output directory parameter.
- Create the directory if it does not exist.
- Collect host metadata.
- Export running services to CSV.
- Export top processes to CSV.
- Export a JSON summary.
- Use
try/catchwith-ErrorAction Stop. - Support
-Verbose. - Use
SupportsShouldProcessso file-writing commands can honor-WhatIf.
Starter Script
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string]$OutputDirectory
)try {
if (-not (Test-Path $OutputDirectory)) {
if ($PSCmdlet.ShouldProcess($OutputDirectory, 'Create output directory')) {
New-Item -ItemType Directory -Path $OutputDirectory -ErrorAction Stop | Out-Null
}
}
$summary = [pscustomobject]@{
ComputerName = $env:COMPUTERNAME
PowerShell = $PSVersionTable.PSVersion.ToString()
OS = $PSVersionTable.OS
Timestamp = (Get-Date).ToString('o')
}
$servicesPath = Join-Path $OutputDirectory 'running-services.csv'
$processesPath = Join-Path $OutputDirectory 'top-processes.csv'
$summaryPath = Join-Path $OutputDirectory 'summary.json'
if ($PSCmdlet.ShouldProcess($servicesPath, 'Export running services')) {
Get-Service |
Where-Object Status -eq 'Running' |
Sort-Object DisplayName |
Select-Object Name, DisplayName, Status |
Export-Csv -Path $servicesPath -NoTypeInformation -ErrorAction Stop
}
if ($PSCmdlet.ShouldProcess($processesPath, 'Export top processes')) {
Get-Process |
Sort-Object CPU -Descending |
Select-Object -First 20 Name, Id, CPU, @{ Name = 'MemoryMB'; Expression = { [math]::Round($_.WorkingSet64 / 1MB, 2) } } |
Export-Csv -Path $processesPath -NoTypeInformation -ErrorAction Stop
}
if ($PSCmdlet.ShouldProcess($summaryPath, 'Export summary JSON')) {
$summary | ConvertTo-Json -Depth 4 | Set-Content -Path $summaryPath -Encoding utf8 -ErrorAction Stop
}
Write-Verbose 'Inventory runbook completed.'
$summary
} catch {
Write-Error -ErrorRecord $_
exit 1
}
Test Plan
.\Inventory.ps1 -OutputDirectory .\out -WhatIf
.\Inventory.ps1 -OutputDirectory .\out -Verbose
Get-ChildItem .\out
Import-Csv .\out\running-services.csv | Select-Object -First 5
Get-Content .\out\summary.json -Raw | ConvertFrom-Json
Production Hardening
- Add a transcript or structured log file.
- Run under a least-privilege service account.
- Store output in a controlled directory.
- Sign scripts if your organization requires AllSigned.
- Add Pester tests for parameter validation and output files.
- Document how the runbook is scheduled and who owns it.
Final Checklist
By the end of this course, you should be able to explain the object pipeline, inspect objects, export structured data, write functions, handle errors, organize modules, run background work, and reason clearly about PowerShell security controls.
- ✓A safe runbook is parameterized, idempotent, logged, and testable
- ✓SupportsShouldProcess enables -WhatIf and -Confirm behavior for changes
- ✓Use Join-Path for output paths and -ErrorAction Stop for catchable failures
- ✓Export both machine-readable summary JSON and analyst-friendly CSV reports
- ✓Production automation needs ownership, least privilege, secret handling, and scheduling documentation
1. What does SupportsShouldProcess enable?
2. Which output pattern is best for an inventory runbook?
Recommended: Pluralsight
This free course covers the theory. Pluralsight adds structured video courses, hands-on Azure labs, and timed practice exams to make it stick before exam day.