Windows Update fails for two dozen reasons and the troubleshooter in Settings catches three of them. The reliable fix is the reset script — stop the services, clear the cache, re-register the engine, repair the component store, restart. The order matters; running the steps out of order is the reason the same script "sometimes works".
Table of Contents
Why a reset works
Windows Update has three moving parts on disk: the SoftwareDistribution directory (download cache), the catroot2 directory (signature catalog) and the registered COM components for the update engine itself. When any of those gets corrupt — failed download, half-applied patch, antivirus quarantine — the whole engine returns generic errors. The reset clears all three.
The correct order
- Stop the services that hold locks.
- Rename the cache directories (do not delete — keep for rollback).
- Re-register the WUA components.
- Run DISM and SFC against the component store.
- Restart the services.
- Force a scan and let it finish.
The PowerShell reset script
$ErrorActionPreference = 'Stop'
$svcs = 'wuauserv','cryptSvc','bits','msiserver'
foreach ($s in $svcs) { Stop-Service $s -Force -ErrorAction SilentlyContinue }
$ts = Get-Date -Format 'yyyyMMddHHmmss'
Rename-Item C:\Windows\SoftwareDistribution "SoftwareDistribution.$ts" -ErrorAction SilentlyContinue
Rename-Item C:\Windows\System32\catroot2 "catroot2.$ts" -ErrorAction SilentlyContinue
# Re-register the engine
$mods = @(
'atl.dll','urlmon.dll','mshtml.dll','shdocvw.dll','browseui.dll','jscript.dll',
'vbscript.dll','scrrun.dll','msxml.dll','msxml3.dll','msxml6.dll','actxprxy.dll',
'softpub.dll','wintrust.dll','dssenh.dll','rsaenh.dll','gpkcsp.dll','sccbase.dll',
'slbcsp.dll','cryptdlg.dll','oleaut32.dll','ole32.dll','shell32.dll','initpki.dll',
'wuapi.dll','wuaueng.dll','wuaueng1.dll','wucltui.dll','wups.dll','wups2.dll',
'wuweb.dll','qmgr.dll','qmgrprxy.dll','wucltux.dll','muweb.dll','wuwebv.dll'
)
foreach ($m in $mods) { regsvr32.exe /s $m }
DISM.exe /Online /Cleanup-Image /RestoreHealth
sfc.exe /scannow
foreach ($s in $svcs) { Start-Service $s }
Get-WindowsUpdateLog -LogPath $env:USERPROFILE\Desktop\WindowsUpdate.log
Write-Host 'Now run: usoclient StartScan'
Verify with PowerShell
Install-Module PSWindowsUpdate -Scope CurrentUser
Get-WindowsUpdate # available updates
Get-WUHistory -MaxDate (Get-Date).AddDays(-7) # recent attempts
Get-WUSettings # WSUS / managed by GP
WSUS-managed hosts
If the host is WSUS-managed and the WSUS server is sick, the local engine cannot recover. Check the upstream:
Get-ItemProperty 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate' WUServer
Test-NetConnection $wsus -Port 8530
Specific error codes
0x80240034— failed download. Reset solves most occurrences.0x80070005— access denied. Antivirus or insufficient disk permission.0x800f0922— pre-install validation. Usually free space on system drive (> 20 GB).0x80244022— proxy / WSUS connectivity.
Audit checklist
- Reset script run cleanly with no errors (1 pt)
- WindowsUpdate.log generated and reviewed (1 pt)
- DISM /RestoreHealth returns no corruption (1 pt)
- SFC /scannow returns no integrity violations (1 pt)
- Test scan completes within 5 minutes (1 pt)
Component-store repair and DISM-driven recovery
Stopping services and clearing SoftwareDistribution fixes about 80% of Windows Update failures. The remaining 20% live in the Component-Based Servicing store (WinSxS) and require DISM to repair against a known-good source.
Detect component-store damage first
DISM /Online /Cleanup-Image /ScanHealth
DISM /Online /Cleanup-Image /CheckHealth
ScanHealth takes 5–10 minutes and reports whether the store is repairable. If it returns "no component store corruption detected" but updates still fail, the issue is somewhere else — usually disk space, WSUS server, or BITS.
Repair against an explicit source
The default RestoreHealth pulls from Windows Update, which is what is broken. Point it at a mounted ISO, a side-by-side install, or a WSUS server's content folder.
REM Mount install.wim from a matching ISO
DISM /Mount-Image /ImageFile:D:\sources\install.wim /Index:1 /MountDir:C:\mount /ReadOnly
REM Repair from the mounted source, prevent fallback to WU
DISM /Online /Cleanup-Image /RestoreHealth `
/Source:WIM:C:\mount\Windows\WinSxS /LimitAccess
DISM /Unmount-Image /MountDir:C:\mount /Discard
Match the WIM build number exactly. Repairing 22H2 from a 21H2 source produces a corrupted system; the symptoms appear weeks later as random app crashes.
Reset the BITS queue properly
BitsAdmin /reset is the documented one-liner, but it leaves orphaned job files in %ALLUSERSPROFILE%\Microsoft\Network\Downloader. After reset, delete that directory's contents and restart BITS:
net stop bits
Remove-Item "$env:ALLUSERSPROFILE\Microsoft\Network\Downloader\*" -Force -Recurse -ErrorAction SilentlyContinue
net start bits
Get-BitsTransfer -AllUsers | Format-Table -AutoSize
Common pitfalls
- Deleting
WinSxS. It looks bloated; deleting it bricks the OS. UseDISM /Cleanup-Image /StartComponentCleanupfor safe size reduction. - Mismatched repair source. Always confirm
winveron the broken machine matches the ISO beforeRestoreHealth. - Forgetting the WSUS client cache. If the box uses WSUS,
wuauclt /resetauthorization /detectnowafter the reset is mandatory; otherwise it keeps talking to the same broken cookie. - Renaming
SoftwareDistributionwhile services run. The rename succeeds, the services recreate the folder immediately, you have changed nothing. Stopwuauserv,cryptsvc,bits,msiserverbefore any rename. - Skipping the disk-space check. Update install needs 8–16 GB of free space depending on the cumulative. A failing update on a 10 GB free disk is a disk-space problem dressed as an update problem.
The 20-minute Windows Update reset script
The exact sequence below has unstuck more update failures than any single one-liner. Save it as reset-wu.ps1, run elevated, expect a reboot at the end.
$ErrorActionPreference = 'Continue'
$svcs = 'wuauserv','cryptsvc','bits','msiserver'
# 1. Stop services
$svcs | ForEach-Object {
Stop-Service $_ -Force -Verbose
Start-Sleep -Seconds 2
}
# 2. Rename caches (renames preserve evidence; deletion does not)
Rename-Item C:\Windows\SoftwareDistribution C:\Windows\SoftwareDistribution.old -ErrorAction SilentlyContinue
Rename-Item C:\Windows\System32\catroot2 C:\Windows\System32\catroot2.old -ErrorAction SilentlyContinue
# 3. Reset BITS jobs
bitsadmin /reset /allusers
Remove-Item "$env:ALLUSERSPROFILE\Microsoft\Network\Downloader\*" -Force -Recurse -ErrorAction SilentlyContinue
# 4. Re-register the WU components
$dlls = 'atl.dll','urlmon.dll','mshtml.dll','shdocvw.dll','browseui.dll','jscript.dll',
'vbscript.dll','scrrun.dll','msxml.dll','msxml3.dll','msxml6.dll','actxprxy.dll',
'softpub.dll','wintrust.dll','dssenh.dll','rsaenh.dll','gpkcsp.dll','sccbase.dll',
'slbcsp.dll','cryptdlg.dll','oleaut32.dll','ole32.dll','shell32.dll','initpki.dll',
'wuapi.dll','wuaueng.dll','wuaueng1.dll','wucltui.dll','wups.dll','wups2.dll',
'wuweb.dll','qmgr.dll','qmgrprxy.dll','wucltux.dll','muweb.dll','wuwebv.dll'
$dlls | ForEach-Object { regsvr32.exe /s $_ }
# 5. Reset Winsock and proxy (rules out NIC/proxy interference)
netsh winsock reset
netsh winhttp reset proxy
# 6. Repair component store while services are stopped
DISM /Online /Cleanup-Image /RestoreHealth
# 7. Restart services
$svcs | ForEach-Object { Start-Service $_ -Verbose }
# 8. Force re-detection
wuauclt /resetauthorization /detectnow
USOClient.exe StartScan
Write-Host "Reset complete. Reboot, then run: Get-WindowsUpdateLog"
The SoftwareDistribution.old and catroot2.old directories survive for forensics. Once the next update cycle completes successfully, schedule their cleanup. Keep them at least 7 days; longer if the failure was unusual.
If the script completes cleanly but updates still fail, the cause is almost certainly upstream: WSUS configuration, SCCM client, an air-gap proxy, or a Microsoft CDN issue in your region. Test-NetConnection -ComputerName windowsupdate.microsoft.com -Port 443 from the affected host is the first diagnostic.
Treating Windows Update as a measured service
Most organisations treat Windows Update as either fully automatic or completely manual, and both extremes produce drift, security gaps, and surprise outages. The pragmatic middle ground is to treat updates as a measured service with explicit success criteria, weekly reporting, and a small set of operational guardrails.
Define the compliance window explicitly. Critical security updates should reach 95% of the fleet within 14 days of release; the remaining 5% are documented exceptions. Cumulative updates can have a longer window — typically 30 days — but the same 95% target. Without an explicit number, "we patch promptly" means whatever the last argument decided, and the gap from intent to reality grows quietly.
Measure compliance per OU. A weekly report broken down by organisational unit shows where patching has stalled. Workstations are usually fine; servers often lag because reboot windows are scarce; specialised systems (lab machines, kiosks) lag because nobody owns them. The OU view exposes the ownership gap and forces the conversation about who is responsible for the trailing systems.
Track failed-update count per host. A single update failure on one host is normal and self-resolves. The same update failing on the same host three weeks running indicates a corrupt component store, a disk-space problem, or a configuration that needs a manual fix. The list of repeat-offender hosts is the queue for the engineer running the reset script — a small, prioritised, finite list rather than an open-ended mandate to "fix update issues".
Pair the metrics with a change-window calendar shared with the application teams. Servers in the calendar reboot automatically inside their window; servers outside it require manual coordination. The calendar removes the most painful conversation in patching — "you rebooted my system without warning" — by making the warning structural and visible weeks ahead.
Within a quarter the metrics tell a clear story: which OUs need attention, which hosts need engineering time, and whether the overall fleet is improving. The reset script described in this guide becomes one tool in a managed service rather than the only thing standing between you and a security finding.
FAQ
Is it safe on a production server?
The script is read-rename-rebuild — nothing is deleted. Take a snapshot or restore point first.
Does this fix feature update failures?
Often. Feature updates also need 20+ GB free, the right driver baseline, and Windows Update healthy.
What about WSUS server-side issues?
Reset on the host does nothing if WSUS itself is broken. Run Get-WsusServer and the WSUS clean-up wizard on the server.
How do I find the actual error code, not just "something failed"?
Get-WindowsUpdateLog on Windows 10/11 produces a unified log on the desktop. Search for "FATAL", "ERROR", and the four-digit hex code; cross-reference at the Microsoft Update Catalog or err.exe.
Do these steps work on Windows Server 2019/2022/2025?
Yes, with one caveat: on Server Core, use PowerShell equivalents (Stop-Service, Rename-Item) since net and cmd shortcuts behave the same but feel awkward in a remote session.
Is sfc /scannow needed before DISM?
The newer guidance is DISM first, SFC second. DISM repairs the store; SFC then uses the repaired store to fix protected files.
How do I prevent a failed update from rolling back forever?
Pause updates, run the reset and DISM repair, then resume. If the same KB fails twice, hide it via PSWindowsUpdate and open a support case — the install package itself may be corrupt in your CDN region.