Skip to main content

How to Clear the Windows Update Cache in Batch Script

Windows Update issues are a common headache for administrators. Updates get stuck, fail to download, or report cryptic error codes, often due to a corrupted local cache. Clearing the Windows Update cache, specifically the SoftwareDistribution and catroot2 folders, is the standard first-aid procedure for resolving these issues. Automating this with a Batch script ensures that services are stopped and restarted in the correct order, which is critical for a successful reset.

This guide explains how to safely reset the Windows Update cache and related components.

Why Clear the Update Cache?

Windows Update Flow:
1. Check for updates → metadata stored in SoftwareDistribution\DataStore
2. Download updates → files stored in SoftwareDistribution\Download
3. Verify signatures → certificates cached in catroot2
4. Install updates → uses downloaded files + signatures

If any step's cached data is corrupt:
→ Updates fail, loop, or show error codes like 0x80070002, 0x80244010
→ Clearing the cache forces fresh downloads of all metadata and files
FolderLocationContents
SoftwareDistribution%SystemRoot%\SoftwareDistributionUpdate metadata, downloaded update files, update history database
catroot2%SystemRoot%\System32\catroot2Cryptographic signatures and certificates for update verification
Administrative Privileges Required

This script stops core system services (wuauserv, cryptSvc, bits, msiserver) and modifies protected system directories. You MUST run as Administrator. Without elevation, the service stop commands and folder operations will fail.

Method 1: Complete Windows Update Cache Reset

This method performs the full reset procedure: stops all related services, renames the cache folders (safer than deleting), restarts services, and verifies the reset.

@echo off
setlocal

echo ============================================================
echo Windows Update Cache Reset Utility
echo ============================================================
echo.

:: =============================================
:: Step 1: Check admin privileges
:: =============================================
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] This script must be run as Administrator. >&2
echo Right-click and select "Run as administrator." >&2
endlocal
exit /b 1
)

echo [OK] Running with administrator privileges.
echo.

:: =============================================
:: Step 2: Stop Windows Update services
:: =============================================
echo [ACTION] Stopping Windows Update services...

:: Stop services in dependency order
for %%s in (wuauserv cryptSvc bits msiserver) do (
echo Stopping %%s...
net stop %%s >nul 2>&1

:: Verify the service actually stopped
sc query %%s 2>nul | findstr /i "STOPPED" >nul 2>&1
if errorlevel 1 (
:: Service may be hung, wait and retry
echo [RETRY] %%s did not stop immediately. Waiting...
timeout /t 5 >nul
net stop %%s >nul 2>&1

sc query %%s 2>nul | findstr /i "STOPPED" >nul 2>&1
if errorlevel 1 (
echo [WARNING] %%s could not be stopped. Attempting to continue... >&2
) else (
echo [OK] %%s stopped.
)
) else (
echo [OK] %%s stopped.
)
)

echo.

:: =============================================
:: Step 3: Rename cache folders
:: =============================================
echo [ACTION] Resetting cache folders...

:: Clean up any previous .old folders
if exist "%SystemRoot%\SoftwareDistribution.old" (
echo Removing previous SoftwareDistribution.old...
rmdir /s /q "%SystemRoot%\SoftwareDistribution.old" 2>nul
)
if exist "%SystemRoot%\System32\catroot2.old" (
echo Removing previous catroot2.old...
rmdir /s /q "%SystemRoot%\System32\catroot2.old" 2>nul
)

:: Rename current folders
set "SDRenamed=FALSE"
set "CRRenamed=FALSE"

if exist "%SystemRoot%\SoftwareDistribution" (
ren "%SystemRoot%\SoftwareDistribution" SoftwareDistribution.old 2>nul
if not errorlevel 1 (
echo [OK] SoftwareDistribution renamed to .old
set "SDRenamed=TRUE"
) else (
echo [WARNING] Could not rename SoftwareDistribution. >&2
echo A file may be locked. Try rebooting and re-running. >&2
)
) else (
echo [INFO] SoftwareDistribution folder does not exist (already clean^).
set "SDRenamed=TRUE"
)

if exist "%SystemRoot%\System32\catroot2" (
ren "%SystemRoot%\System32\catroot2" catroot2.old 2>nul
if not errorlevel 1 (
echo [OK] catroot2 renamed to .old
set "CRRenamed=TRUE"
) else (
echo [WARNING] Could not rename catroot2. >&2
echo This folder is sometimes locked by the crypto service. >&2
)
) else (
echo [INFO] catroot2 folder does not exist (already clean^).
set "CRRenamed=TRUE"
)

echo.

:: =============================================
:: Step 4: Reset BITS transfer queue
:: =============================================
echo [ACTION] Clearing BITS transfer queue...
del /q /f "%ALLUSERSPROFILE%\Microsoft\Network\Downloader\qmgr*.dat" 2>nul
echo [OK] BITS queue cleared.

echo.

:: =============================================
:: Step 5: Restart services
:: =============================================
echo [ACTION] Restarting Windows Update services...

for %%s in (wuauserv cryptSvc bits msiserver) do (
net start %%s >nul 2>&1
if not errorlevel 1 (
echo [OK] %%s started.
) else (
echo [WARNING] %%s did not start. It may start automatically later. >&2
)
)

echo.

:: =============================================
:: Step 6: Verify the reset
:: =============================================
echo [INFO] Verification:

:: Check if new SoftwareDistribution was created
if exist "%SystemRoot%\SoftwareDistribution" (
echo [OK] Fresh SoftwareDistribution folder created by Windows Update service.
) else (
echo [INFO] SoftwareDistribution will be recreated on the next update check.
)

:: Check if Windows Update service is running
sc query wuauserv 2>nul | findstr /i "RUNNING" >nul 2>&1
if not errorlevel 1 (
echo [OK] Windows Update service is running.
) else (
echo [WARNING] Windows Update service is not running. >&2
echo It should start automatically. If not, run: net start wuauserv >&2
)

echo.
echo ============================================================
echo Cache reset complete.
echo ============================================================
echo.
echo Next steps:
echo 1. Open Settings ^> Windows Update
echo 2. Click "Check for updates"
echo 3. Updates should download fresh copies
echo.

if "%SDRenamed%"=="TRUE" (
echo [CLEANUP] After confirming updates work, delete the old folders:
echo rmdir /s /q "%SystemRoot%\SoftwareDistribution.old"
echo rmdir /s /q "%SystemRoot%\System32\catroot2.old"
)

:: Log the operation
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] UPDATE CACHE RESET on %COMPUTERNAME% by %USERNAME% >> "%~dp0update_maintenance.log"

endlocal
exit /b 0

Why rename instead of delete:

Rename Is Safer Than Delete

Renaming the folders (to .old) instead of deleting them provides a safety net:

  • If something goes wrong, the original folders still exist and can be renamed back.
  • Windows automatically creates fresh, empty SoftwareDistribution and catroot2 folders when the services restart.
  • The .old folders can be deleted later once updates are working correctly.

This is especially important for catroot2, which contains certificate data that is difficult to regenerate if the delete fails partway.

Why the BITS queue is cleared:

The Background Intelligent Transfer Service (BITS) manages the actual file downloads for Windows Update. Clearing qmgr*.dat removes any stuck or corrupted transfer jobs. Without this step, BITS may continue retrying a broken download even after the SoftwareDistribution folder has been reset.

Why services are stopped in a specific order:

  • wuauserv (Windows Update): The primary consumer of the cache folders.
  • cryptSvc (Cryptographic Services): Uses catroot2 for signature verification.
  • bits (Background Intelligent Transfer Service): Manages downloads.
  • msiserver (Windows Installer): Handles .msi package installation.

All four must be stopped before the cache folders can be renamed, because any running service may have file handles open on files within those directories.

Method 2: Extended Reset (Network Reset + Component Re-registration)

For persistent Windows Update failures that survive a basic cache reset, this method adds Winsock reset, proxy reset, and DLL re-registration.

@echo off
setlocal

echo ============================================================
echo Extended Windows Update Reset
echo ============================================================
echo.

net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)

:: Phase 1: Stop services (same as Method 1)
echo [1/4] Stopping services...
for %%s in (wuauserv cryptSvc bits msiserver) do (
net stop %%s >nul 2>&1
)
echo [OK] Services stopped.
echo.

:: Phase 2: Clear caches (same as Method 1)
echo [2/4] Clearing caches...
if exist "%SystemRoot%\SoftwareDistribution.old" rmdir /s /q "%SystemRoot%\SoftwareDistribution.old" 2>nul
if exist "%SystemRoot%\System32\catroot2.old" rmdir /s /q "%SystemRoot%\System32\catroot2.old" 2>nul

ren "%SystemRoot%\SoftwareDistribution" SoftwareDistribution.old 2>nul
ren "%SystemRoot%\System32\catroot2" catroot2.old 2>nul

del /q /f "%ALLUSERSPROFILE%\Microsoft\Network\Downloader\qmgr*.dat" 2>nul
echo [OK] Caches cleared.
echo.

:: Phase 3: Reset network components
echo [3/4] Resetting network components...

:: Reset Winsock catalog
netsh winsock reset >nul 2>&1
echo [OK] Winsock catalog reset.

:: Reset proxy settings (if Windows Update is using a proxy)
netsh winhttp reset proxy >nul 2>&1
echo [OK] WinHTTP proxy reset to direct.

:: Flush DNS
ipconfig /flushdns >nul 2>&1
echo [OK] DNS cache flushed.

echo.

:: Phase 4: Re-register Windows Update DLLs
echo [4/4] Re-registering Windows Update components...

for %%d in (
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 wuapi.dll wuaueng.dll
wuaueng1.dll wucltui.dll wups.dll wups2.dll wuweb.dll
qmgr.dll qmgrprxy.dll wucltux.dll muweb.dll wuwebv.dll
) do (
regsvr32 /s %%d >nul 2>&1
)
echo [OK] DLLs re-registered.
echo.

:: Restart services
echo [INFO] Restarting services...
for %%s in (wuauserv cryptSvc bits msiserver) do (
net start %%s >nul 2>&1
)
echo [OK] Services restarted.

echo.
echo ============================================================
echo Extended reset complete.
echo ============================================================
echo.
echo A REBOOT is recommended after an extended reset.
echo After rebooting, check for updates in Settings.

for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] EXTENDED UPDATE RESET on %COMPUTERNAME% by %USERNAME% >> "%~dp0update_maintenance.log"

endlocal
exit /b 0
When to Use Extended Reset

The extended reset (Method 2) should only be used when the basic reset (Method 1) doesn't resolve the issue. Re-registering DLLs and resetting Winsock are aggressive operations that modify system-wide network and COM registration settings. On a healthy system, they are unnecessary. Use Method 1 first, try updating, and only escalate to Method 2 if failures persist.

When to use Method 1 vs. Method 2:

SymptomMethod
Updates stuck downloading at a percentageMethod 1
Error code 0x80070002 or 0x80244010Method 1
Updates fail after successful downloadMethod 1, then Method 2
"Something went wrong" with no specific errorMethod 1, then Method 2
Updates worked after cache reset but failed againMethod 2
Nothing works, multiple error codesMethod 2 + DISM repair

Method 3: Check Windows Update Status After Reset

After running either reset method, verify that Windows Update is functional.

@echo off
setlocal EnableDelayedExpansion

echo ============================================================
echo Windows Update Status Verification
echo ============================================================
echo.
echo Computer: %COMPUTERNAME%
echo Date: %date% %time%
echo.
echo ============================================================
echo.

:: ============================================================
:: Check 1: Windows Update Services Status
:: ============================================================

echo ============================================================
echo Service Status
echo ============================================================
echo.

set "AllRunning=1"
set "ServicesChecked=0"
set "ServicesRunning=0"

for %%s in (wuauserv cryptSvc bits msiserver) do (
set /a ServicesChecked+=1
set "ServiceState=UNKNOWN"

for /f "tokens=4" %%a in (
'sc query %%s 2^>nul ^| findstr "STATE"'
) do (
set "ServiceState=%%a"
)

if /i "!ServiceState!"=="RUNNING" (
echo [OK] %%s: !ServiceState!
set /a ServicesRunning+=1
) else if /i "!ServiceState!"=="STOPPED" (
echo [KO] %%s: !ServiceState!
set "AllRunning=0"
) else if /i "!ServiceState!"=="UNKNOWN" (
echo [??] %%s: Service not found
set "AllRunning=0"
) else (
echo [--] %%s: !ServiceState!
set "AllRunning=0"
)
)

echo.
echo Status: !ServicesRunning! / !ServicesChecked! services running
echo.

:: ============================================================
:: Check 2: Cache Directories
:: ============================================================

echo ============================================================
echo Cache Status
echo ============================================================
echo.

:: Check SoftwareDistribution
set "SDPath=%SystemRoot%\SoftwareDistribution"

if exist "!SDPath!\" (
echo SoftwareDistribution: EXISTS
echo Location: !SDPath!

:: Check Download folder
if exist "!SDPath!\Download\" (
set "DownloadCount=0"

for /f %%n in (
'dir /b /a "!SDPath!\Download\" 2^>nul ^| find /c /v ""'
) do set "DownloadCount=%%n"

echo Download Cache: !DownloadCount! item(s^)

if !DownloadCount! equ 0 (
echo Status: Fresh/Empty
) else (
echo Status: Contains data
)
) else (
echo Download Cache: Folder does not exist yet
echo Status: Will be created on first update
)
) else (
echo SoftwareDistribution: MISSING
echo Status: Will be created when service starts
)

echo.

:: Check catroot2
set "CatRoot2=%SystemRoot%\System32\catroot2"

if exist "!CatRoot2!\" (
echo catroot2: EXISTS
echo Location: !CatRoot2!
) else (
echo catroot2: MISSING
echo Status: Will be recreated automatically
)

echo.

:: ============================================================
:: Check 3: Pending Updates
:: ============================================================

echo ============================================================
echo Update Availability Check
echo ============================================================
echo.

echo Querying Windows Update for available updates...
echo (This may take 10-30 seconds^)
echo.

:: Build PowerShell command
set "PSCmd=try {"
set "PSCmd=!PSCmd! $session = New-Object -ComObject Microsoft.Update.Session;"
set "PSCmd=!PSCmd! $searcher = $session.CreateUpdateSearcher();"
set "PSCmd=!PSCmd! Write-Host 'Searching for updates...' -ForegroundColor Cyan;"
set "PSCmd=!PSCmd! $result = $searcher.Search('IsInstalled=0');"
set "PSCmd=!PSCmd! $updates = $result.Updates;"
set "PSCmd=!PSCmd! $count = $updates.Count;"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! if ($count -eq 0) {"
set "PSCmd=!PSCmd! Write-Host '[OK] No pending updates found' -ForegroundColor Green;"
set "PSCmd=!PSCmd! Write-Host 'System is up to date' -ForegroundColor Green"
set "PSCmd=!PSCmd! } else {"
set "PSCmd=!PSCmd! Write-Host \"[INFO] $count update(s) available:\" -ForegroundColor Yellow;"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! $i = 1;"
set "PSCmd=!PSCmd! foreach ($u in $updates) {"
set "PSCmd=!PSCmd! Write-Host \" $i. $($u.Title)\";"
set "PSCmd=!PSCmd! $i++"
set "PSCmd=!PSCmd! };"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! Write-Host 'Install via: Settings > Windows Update' -ForegroundColor Cyan"
set "PSCmd=!PSCmd! };"
set "PSCmd=!PSCmd! exit 0"
set "PSCmd=!PSCmd! } catch {"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! Write-Host '[WARNING] Could not check for updates' -ForegroundColor Yellow;"
set "PSCmd=!PSCmd! Write-Host \"Error: $($_.Exception.Message)\" -ForegroundColor Yellow;"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! Write-Host 'Possible reasons:' -ForegroundColor Cyan;"
set "PSCmd=!PSCmd! Write-Host ' - Windows Update service not ready yet';"
set "PSCmd=!PSCmd! Write-Host ' - Internet connection issue';"
set "PSCmd=!PSCmd! Write-Host ' - Windows Update components still initializing';"
set "PSCmd=!PSCmd! Write-Host '';"
set "PSCmd=!PSCmd! Write-Host 'Try checking manually: Settings > Windows Update' -ForegroundColor Cyan;"
set "PSCmd=!PSCmd! exit 1"
set "PSCmd=!PSCmd! }"

powershell -NoProfile -ExecutionPolicy Bypass -Command "!PSCmd!"

set "UpdateCheckResult=!errorlevel!"

echo.

:: ============================================================
:: Check 4: Last Update Check Time
:: ============================================================

echo ============================================================
echo Last Update Check
echo ============================================================
echo.

set "PSTime=try {"
set "PSTime=!PSTime! $wu = New-Object -ComObject Microsoft.Update.AutoUpdate;"
set "PSTime=!PSTime! $lastCheck = $wu.Results.LastSearchSuccessDate;"
set "PSTime=!PSTime! if ($lastCheck) {"
set "PSTime=!PSTime! Write-Host \"Last successful check: $lastCheck\""
set "PSTime=!PSTime! } else {"
set "PSTime=!PSTime! Write-Host 'No recent update check recorded'"
set "PSTime=!PSTime! }"
set "PSTime=!PSTime! } catch {"
set "PSTime=!PSTime! Write-Host 'Could not retrieve last check time'"
set "PSTime=!PSTime! }"

powershell -NoProfile -Command "!PSTime!" 2>nul

echo.

:: ============================================================
:: Overall Assessment
:: ============================================================

echo ============================================================
echo Overall Assessment
echo ============================================================
echo.

set "HealthScore=0"
set "MaxScore=2"

:: Service check
if !AllRunning! equ 1 (
echo [OK] All critical services are running
set /a HealthScore+=1
) else (
echo [ ] Not all services are running
echo Start services: net start wuauserv
)

:: Update check
if !UpdateCheckResult! equ 0 (
echo [OK] Windows Update is responsive
set /a HealthScore+=1
) else (
echo [ ?] Windows Update check had issues
echo Recommendation: Wait 5 minutes and try again
)

echo.
echo Health Score: !HealthScore! / !MaxScore!
echo.

if !HealthScore! equ !MaxScore! (
echo ============================================================
echo Status: HEALTHY
echo ============================================================
echo.
echo Windows Update appears to be functioning normally.
echo.
set "ExitCode=0"

) else if !HealthScore! geq 1 (
echo ============================================================
echo Status: PARTIALLY FUNCTIONAL
echo ============================================================
echo.
echo Windows Update has minor issues.
echo.
echo Recommendations:
echo - Restart Windows Update service
echo - Check internet connection
echo - Wait a few minutes for initialization
echo - Try checking for updates manually
echo.
set "ExitCode=1"

) else (
echo ============================================================
echo Status: NOT FUNCTIONAL
echo ============================================================
echo.
echo Windows Update has significant issues.
echo.
echo Troubleshooting Steps:
echo 1. Restart all Windows Update services:
for %%s in (wuauserv cryptSvc bits) do (
echo net start %%s
)
echo.
echo 2. Run Windows Update Troubleshooter:
echo Settings ^> Troubleshoot ^> Windows Update
echo.
echo 3. If still failing, consider cache reset:
echo Run update cache reset script
echo.
set "ExitCode=2"
)

echo ============================================================
echo.

pause
endlocal
exit /b !ExitCode!

How to Avoid Common Errors

Wrong Way: Deleting Files While Services Are Running

:: FAILS: services have file handles open on these directories
del /q /s C:\Windows\SoftwareDistribution\*
:: Result: "Access is denied" or "The process cannot access the file"

If the Windows Update, BITS, or Cryptographic Services have files open in the cache directories, delete and rename operations fail.

Correct Way: Stop ALL related services before touching the directories. Method 1 stops four services and verifies each one actually stopped.

Wrong Way: Deleting Instead of Renaming

:: RISKY: if deletion is interrupted, partial state is worse
rmdir /s /q C:\Windows\SoftwareDistribution
:: If this fails halfway, the folder is partially deleted, corrupted

A partial deletion leaves the folder in a worse state than before the reset. Renaming is atomic, it either succeeds completely or fails without modifying the original.

Correct Way: Rename to .old, then delete the .old folder later after confirming updates work.

Problem: Service Refuses to Stop ("Stop Pending")

The wuauserv service sometimes enters a "Stop Pending" state and hangs for minutes. net stop returns but the service isn't actually stopped.

Solution: Method 1 includes a retry with delay. For severely hung services, a forced termination may be needed:

:: Last resort, force-kill the service process
taskkill /f /fi "services eq wuauserv" >nul 2>&1
Force-Killing Services

Force-killing a service with taskkill /f can leave the service in an inconsistent state. Use this only as a last resort when the service is completely unresponsive. After force-killing, restart the service with net start to reinitialize it.

Problem: catroot2 Folder Won't Rename

The catroot2 folder is sometimes locked even after stopping cryptSvc, because other system components hold references to the certificate database.

Solution: Wait 10–15 seconds after stopping the service, then retry. If it still fails, a reboot may be necessary before the reset can be completed.

Problem: Update History Is Lost

Resetting the SoftwareDistribution folder clears the update history database. The Settings > Windows Update > Update History page will show no history. The updates themselves are still installed, only the log of when they were installed is cleared.

Solution: This is expected behavior, not an error. If historical tracking is important, export the update history before the reset:

powershell -NoProfile -Command "Get-HotFix | Export-Csv '%~dp0update_history_before_reset.csv' -NoTypeInformation"

Best Practices and Rules

1. Try Method 1 Before Method 2

The basic cache reset resolves the majority of Windows Update issues. Only escalate to the extended reset if the basic reset doesn't resolve the problem.

2. Rename, Don't Delete

Renaming is reversible. Deleting is not. Keep the .old folders until you've confirmed updates work, then delete them to reclaim space.

3. Verify After Reset

After resetting, open Settings > Windows Update and click "Check for updates." If the update downloads and installs successfully, the reset worked. Method 3 provides automated verification.

4. Export Update History Before Reset

The SoftwareDistribution folder contains the update history database. If you need this record, export it before resetting.

5. Reboot After Extended Reset

Method 2's Winsock reset and DLL re-registration may require a reboot to take full effect. Always reboot after an extended reset.

6. Schedule Regular Cache Cleanup

For machines with recurring Windows Update problems, schedule a monthly cache reset (Method 1) as preventive maintenance. This clears accumulated corrupt metadata before it causes failures.

Conclusion

Clearing the Windows Update cache is the standard first response to update failures. By stopping services in the correct order, renaming (not deleting) cache folders, clearing the BITS transfer queue, and verifying service restart, you create a reliable reset procedure that resolves the majority of update issues. For persistent failures, the extended reset adds network component reset and DLL re-registration. Always verify updates work after the reset and keep the .old folders until you've confirmed success.