The 2 AM Page That Started This Post
A managed services client called us at 2 AM because a fleet of 180 Windows Server 2022 boxes had stopped autoloading their LOB agent after a botched GPO push. The PowerShell registry provider is what got us back to green by 3:15 AM. One script, one pipeline, 180 servers fixed.
This is the post-mortem. I’ll show you the manual way nobody should ever do again, then the script we wrote live on the bridge.
Incident Timeline
01:52 — Monitoring flags 180 servers missing their agent heartbeat.
02:04 — On-call engineer RDPs into the first box. Opens regedit.exe. Hunts through HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. The autorun entry is gone.
02:18 — Same engineer has fixed three servers. 177 to go. Pages me.
02:22 — I open PowerShell 7.4 and start writing.
Root Cause Analysis
A junior admin had pushed a GPO preference that deleted any Run key matching a wildcard. The wildcard was too greedy. Every server lost its agent autorun entry in HKLM.
The fix needed three things: discover which servers were affected, restore the missing Run value, and confirm it stuck. Doing that by hand across 180 servers? Three days of clicking. Doing it with the registry provider? Eleven minutes.
The Manual Way (Don’t Do This)
Open regedit. Connect to remote registry. Navigate the tree by clicking. Right-click, New, String Value. Type the path. Done. Then do it 179 more times.
Want to know why we built our entire multi-machine PowerShell practice around providers? Because regedit doesn’t scale. Ever.
Version 1: The Quick and Dirty Script
Here’s the ugly first pass I typed on the call. Works, but I wouldn’t show it in a code review.
# v1 — ugly but works at 2 AM
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Get-ItemProperty -Path .\ | Format-List
New-ItemProperty -Path . -Name 'LOBAgent' -Value 'C:\Program Files\LOBAgent\agent.exe' -PropertyType String
The magic? Set-Location HKLM:. PowerShell exposes the Windows Registry through a navigation provider. The same cmdlets you use for files — Set-Location, Get-ChildItem, New-Item, Remove-Item — work on the registry. The HKLM: and HKCU: drives are built in. You can list them yourself.
Get-PSDrive -PSProvider Registry | Select-Object Name, Root
That returns the two default drives: HKCU mapped to HKEY_CURRENT_USER, HKLM mapped to HKEY_LOCAL_MACHINE. Want HKEY_CLASSES_ROOT as a drive? Use New-PSDrive. The provider model treats every data store the same way, which is the whole point.
Version 2: Reading Before Writing
Before I wrote anything in production, I wanted to confirm which servers were actually missing the key. Get-ItemProperty is the read cmdlet. It returns a PSObject with every value under the key as a property.
# v2 — check first, change second
$path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
$current = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue
if (-not $current.LOBAgent) {
Write-Warning "Missing on $env:COMPUTERNAME"
}
Notice Get-Item versus Get-ItemProperty. Get-Item fetches the key object itself. Get-ItemProperty fetches the named values inside. Mix them up and you’ll waste 20 minutes wondering why your property is null. I have, more than once.
Version 3: Making It Production-Ready
For the actual fix we wrapped it in Invoke-Command and hit every server in parallel. Splatting keeps the parameters readable.
# v3 — production fix, ran against 180 boxes
$servers = Get-Content .\affected-hosts.txt
$fix = {
$params = @{
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
Name = 'LOBAgent'
Value = 'C:\Program Files\LOBAgent\agent.exe'
PropertyType = 'String'
Force = $true
}
if (-not (Get-ItemProperty -Path $params.Path -Name $params.Name -ErrorAction SilentlyContinue)) {
New-ItemProperty @params | Out-Null
"$env:COMPUTERNAME : restored"
} else {
"$env:COMPUTERNAME : already present"
}
}
Invoke-Command -ComputerName $servers -ScriptBlock $fix -ThrottleLimit 32
Eleven minutes, end to end. The same approach saved us during a separate engagement where we had to roll out enforced authentication policies across a healthcare client’s domain controllers.
The Opinion Nobody Asked For
If you’re still using reg.exe in 2026, you’re working too hard. The registry provider gives you tab completion, object output, and the full PowerShell pipeline. reg query gives you string parsing and regrets.
That said, here’s the caveat. ACLs absolutely apply. Get-ChildItem HKLM:\SECURITY will throw AccessDenied even as SYSTEM unless you elevate the token properly. And remote registry over WinRM still requires the Remote Registry service or an Invoke-Command session — there’s no magical \\server\HKLM: path. We learned that the hard way on an engagement with a locked-down financial services environment.
What We Changed After the Incident
Three things came out of the post-mortem. First, we now baseline every managed server’s Run keys nightly and diff against the previous snapshot — same pattern we use to monitor our backup strategy jobs. Second, registry-modifying GPOs now get peer-reviewed before deployment. Third, we added a tiny Test-RegistryValue helper to our internal module so nobody writes that -ErrorAction SilentlyContinue dance twice.
function Test-RegistryValue {
param([string]$Path, [string]$Name)
try {
Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop | Out-Null
$true
} catch { $false }
}
If you’re running Windows fleets and you don’t have a paved road for registry remediation yet, that’s a conversation worth having. Reach out at clients.sse.to/contact.php and we’ll show you the runbook.
Lessons Learned
The registry provider isn’t a trick or a hack. It’s the same abstraction that makes cd, dir, and Get-Content work on files, certificates, environment variables, and IIS. Learn one set of cmdlets, navigate every data store. For deeper reading, Microsoft’s Get-Help Registry is genuinely useful, and MITRE ATT&CK documents how attackers abuse those same Run keys — worth knowing before you script changes to them.
Practical takeaway: next time you reach for regedit, type Set-Location HKLM: instead. You’ll never go back, and your future self at 2 AM will thank you.


