Skip to main content

How to Trigger a Windows Update Check in Batch Script

Manually checking for Windows updates through the Settings menu is tedious, especially when managing multiple systems or completing a fresh installation. Automating this check via a Batch script ensures that systems stay patched as part of deployment routines, maintenance schedules, or post-setup workflows. Windows 10/11 provides the Update Session Orchestrator (usoclient.exe) for triggering update operations, and PowerShell's COM-based Windows Update API for detailed query and reporting.

This guide explains how to trigger, monitor, and report on Windows Update operations from Batch scripts.

Understanding the Update Tools

ToolPurposeBest For
usoclient.exeTriggers update scan, download, installSimple trigger, no feedback
wuauclt.exeLegacy update detectionCompatibility with older scripts
PowerShell COM APIQuery, list, and install updates with full controlDetailed reporting, automation

How Windows Update works internally:

Update Process Flow:
1. SCAN → usoclient StartScan → Contacts update servers, builds list
2. DOWNLOAD → usoclient StartDownload → Downloads approved updates
3. INSTALL → usoclient StartInstall → Installs downloaded updates
4. REBOOT → (if required) → Finalizes pending installations
These Commands Trigger Background Operations

usoclient commands trigger the update process but provide NO console output or progress indication. The operations run silently in the background through the Windows Update service. Check Settings → Windows Update to see the progress.

Method 1: Trigger Update Check and Download

The standard approach for ensuring a system is up-to-date: scan for updates and begin downloading anything available.

Implementation

@echo off
setlocal

echo ============================================================
echo Windows Update Trigger
echo ============================================================
echo.

:: Check admin rights (usoclient requires elevation)
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Windows Update operations require administrator privileges. >&2
echo Right-click and select "Run as administrator." >&2
endlocal
exit /b 1
)

:: =============================================
:: Step 1: Verify update services are running
:: =============================================
echo [1/3] Verifying Windows Update services...

:: Check and start the Windows Update service
sc query wuauserv | findstr /i "RUNNING" >nul 2>&1
if errorlevel 1 (
echo [INFO] Starting Windows Update service...
net start wuauserv >nul 2>&1
if errorlevel 1 (
echo [ERROR] Could not start Windows Update service. >&2
echo Updates may be disabled by Group Policy. >&2
endlocal
exit /b 1
)
)
echo [OK] Windows Update service is running.

:: Check BITS (Background Intelligent Transfer Service)
sc query bits | findstr /i "RUNNING" >nul 2>&1
if errorlevel 1 (
echo [INFO] Starting BITS service...
net start bits >nul 2>&1
)
echo [OK] BITS service is running.

:: =============================================
:: Step 2: Trigger the update scan
:: =============================================
echo.
echo [2/3] Initiating update scan...

usoclient StartScan

echo [OK] Scan triggered. Windows Update is checking for updates in the background.

:: =============================================
:: Step 3: Trigger download of available updates
:: =============================================
echo.
echo [3/3] Requesting download of available updates...

usoclient StartDownload

echo [OK] Download triggered. Updates will download in the background.

echo.
echo ============================================================
echo Update check is running in the background.
echo Monitor progress in: Settings -> Windows Update
echo ============================================================
echo.

:: Check if a reboot is already pending from previous updates
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" >nul 2>&1
if not errorlevel 1 (
echo [INFO] A reboot is PENDING from previous updates.
echo Install pending updates by restarting the computer.
echo.
)

endlocal
exit /b 0

Why services are checked first:

usoclient StartScan depends on the Windows Update service (wuauserv) and BITS to function. If either service is stopped (common after troubleshooting or on managed systems with delayed starts), the scan command fails silently: it returns no error, but no scan occurs.

Why the pending-reboot check:

If previous updates are waiting for a reboot to complete installation, new updates may not appear until the pending ones are finalized. The script checks the RebootRequired registry key and informs the administrator.

Group Policy May Block These Commands

On enterprise-managed computers (WSUS, SCCM, Intune), the "Check for updates" function may be controlled by Group Policy. If updates are managed centrally, usoclient commands may be ignored or blocked. The script will appear to succeed, but no scan occurs. Check with your IT department if you're on a managed network.

Method 2: List Available Updates (PowerShell)

usoclient provides no feedback about what updates are available. This method uses the Windows Update COM API through PowerShell to search for and list all pending updates, with details about each one.

@echo off
setlocal

echo [INFO] Searching for available Windows updates...
echo [INFO] This may take 1-5 minutes...
echo.

powershell -NoProfile -Command ^
"try {" ^
" $session = New-Object -ComObject 'Microsoft.Update.Session';" ^
" $searcher = $session.CreateUpdateSearcher();" ^
" Write-Host 'Contacting Windows Update servers...';" ^
" $result = $searcher.Search('IsInstalled=0 and Type=''Software'' and IsHidden=0');" ^
" $updates = $result.Updates;" ^
" if ($updates.Count -eq 0) {" ^
" Write-Host '';" ^
" Write-Host '[OK] No updates available. The system is up to date.';" ^
" exit 0" ^
" };" ^
" Write-Host '';" ^
" Write-Host \"Found $($updates.Count) available update(s):\";" ^
" Write-Host '';" ^
" foreach ($u in $updates) {" ^
" $sizeMB = [math]::Round($u.MaxDownloadSize / 1MB, 1);" ^
" $type = if ($u.MsrcSeverity) { \"[$($u.MsrcSeverity)]\" } else { '[Update]' };" ^
" Write-Host \" $type $($u.Title) ($sizeMB MB)\"" ^
" };" ^
" Write-Host '';" ^
" $totalMB = [math]::Round(($updates | ForEach-Object { $_.MaxDownloadSize } | Measure-Object -Sum).Sum / 1MB, 1);" ^
" Write-Host \"Total download size: $totalMB MB\";" ^
" $critical = ($updates | Where-Object { $_.MsrcSeverity -eq 'Critical' }).Count;" ^
" $important = ($updates | Where-Object { $_.MsrcSeverity -eq 'Important' }).Count;" ^
" if ($critical -gt 0) { Write-Host \" [!] $critical CRITICAL update(s) - install promptly\" };" ^
" if ($important -gt 0) { Write-Host \" [!] $important IMPORTANT update(s)\" };" ^
" exit $updates.Count" ^
"} catch {" ^
" Write-Error $_.Exception.Message;" ^
" exit -1" ^
"}"

set "UpdateCount=%errorlevel%"

echo.

if %UpdateCount% gtr 0 (
echo [INFO] %UpdateCount% update(s) available
echo [INFO] Run Method 1 to trigger download and installation
) else if %UpdateCount% equ 0 (
echo [OK] System is fully up to date
)

endlocal
exit /b 0

Sample output:

Contacting Windows Update servers...

Found 4 available update(s):

[Critical] 2024-05 Cumulative Update for Windows 11 (KB5037771) (312.5 MB)
[Important] 2024-05 .NET Framework 3.5 and 4.8.1 Update (KB5037849) (47.2 MB)
[Update] Intel - System - 12/15/2023 (1.0 MB)
[Update] Microsoft Defender Antivirus Security Intelligence Update (2.8 MB)

Total download size: 363.5 MB
[!] 1 CRITICAL update(s) - install promptly
[!] 1 IMPORTANT update(s)

Why the COM API instead of usoclient:

usoclient is a "fire and forget" tool: it triggers operations but provides zero feedback. The COM API (Microsoft.Update.Session) returns structured objects with full update details: title, size, severity, KB number, and installation state. This is essential for reporting and decision-making.

Filtering Update Types

The search string 'IsInstalled=0 and Type=''Software'' and IsHidden=0' finds software updates that are not installed and not hidden. Other useful filters:

IsInstalled=0 All pending updates (software + drivers)
IsInstalled=0 and Type='Driver' Pending driver updates only
IsInstalled=1 All installed updates
IsInstalled=0 and BrowseOnly=0 Updates approved for install (not browse-only)

Method 3: Check and Install Updates Automatically

For maintenance scripts that should fully automate the update process: scan, download, install, and report whether a reboot is needed.

@echo off
setlocal

echo ============================================================
echo Automated Windows Update (Scan + Install)
echo ============================================================
echo.

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

:: Ensure services are running
net start wuauserv >nul 2>&1
net start bits >nul 2>&1

echo [ACTION] Searching for updates, downloading, and installing...
echo [INFO] This may take 15-60 minutes depending on update size
echo.

powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"try {" ^
" $session = New-Object -ComObject 'Microsoft.Update.Session';" ^
" $searcher = $session.CreateUpdateSearcher();" ^
" Write-Host '[1/3] Scanning for updates...';" ^
" $result = $searcher.Search('IsInstalled=0 and Type=''Software'' and IsHidden=0');" ^
" $updates = $result.Updates;" ^
" if ($updates.Count -eq 0) {" ^
" Write-Host '[OK] System is fully up to date. No updates to install.';" ^
" exit 0" ^
" };" ^
" Write-Host \"Found $($updates.Count) update(s). Downloading...\";" ^
" Write-Host '';" ^
" $updatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl';" ^
" foreach ($u in $updates) {" ^
" if (-not $u.EulaAccepted) { $u.AcceptEula() };" ^
" $updatesToInstall.Add($u) | Out-Null;" ^
" Write-Host \" $($u.Title)\"" ^
" };" ^
" Write-Host '';" ^
" Write-Host '[2/3] Downloading updates...';" ^
" $downloader = $session.CreateUpdateDownloader();" ^
" $downloader.Updates = $updatesToInstall;" ^
" $downloadResult = $downloader.Download();" ^
" Write-Host \" Download result: $($downloadResult.ResultCode)\";" ^
" Write-Host '';" ^
" Write-Host '[3/3] Installing updates...';" ^
" $installer = $session.CreateUpdateInstaller();" ^
" $installer.Updates = $updatesToInstall;" ^
" $installResult = $installer.Install();" ^
" Write-Host \" Install result: $($installResult.ResultCode)\";" ^
" Write-Host '';" ^
" if ($installResult.RebootRequired) {" ^
" Write-Host '[INFO] A REBOOT IS REQUIRED to complete the installation.';" ^
" exit 2" ^
" } else {" ^
" Write-Host '[OK] All updates installed successfully. No reboot needed.';" ^
" exit 0" ^
" }" ^
"} catch {" ^
" Write-Error $_.Exception.Message;" ^
" exit 1" ^
"}"

set "UpdateResult=%errorlevel%"

echo.

if %UpdateResult% equ 2 (
echo [INFO] A reboot is required to finalize the updates.
echo.
set /p "Reboot=Reboot now? (YES/no): "
if /i "!Reboot!"=="YES" (
shutdown /r /t 60 /c "Windows Update - restarting to complete installation."
)
)

endlocal
exit /b 0
Automatic Installation Warning

Method 3 automatically INSTALLS updates without individual approval. On production servers, this can cause unplanned reboots or break applications if an update has compatibility issues. Use this method only on:

  • Workstations during maintenance windows
  • Test/development machines
  • Non-production servers

For production servers, use Method 2 (list only) to review updates before approving installation.

Result codes from the COM API:

CodeMeaning
0Not started
1In progress
2Succeeded
3Succeeded with errors
4Failed
5Aborted

Method 4: Fleet-Wide Update Status Report

For administrators managing multiple machines, collect the update status from each machine into a central CSV.

@echo off
setlocal

set "CSVFile=\\Server\Audit\update_status.csv"

if not exist "%CSVFile%" (
echo "Timestamp","Computer","PendingUpdates","CriticalCount","RebootRequired","LastCheckTime" > "%CSVFile%" 2>nul
)

powershell -NoProfile -Command ^
"$ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss';" ^
"try {" ^
" $searcher = (New-Object -ComObject 'Microsoft.Update.Session').CreateUpdateSearcher();" ^
" $result = $searcher.Search('IsInstalled=0 and IsHidden=0');" ^
" $pending = $result.Updates.Count;" ^
" $critical = ($result.Updates | Where-Object { $_.MsrcSeverity -eq 'Critical' }).Count;" ^
" $reboot = if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') { 'Yes' } else { 'No' };" ^
" $lastCheck = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Detect' -ErrorAction SilentlyContinue).LastSuccessTime;" ^
" Write-Output ('\"' + $ts + '\",\"' + $env:COMPUTERNAME + '\",\"' + $pending + '\",\"' + $critical + '\",\"' + $reboot + '\",\"' + $lastCheck + '\"')" ^
"} catch {" ^
" Write-Output ('\"' + $ts + '\",\"' + $env:COMPUTERNAME + '\",\"ERROR\",\"0\",\"Unknown\",\"Unknown\"')" ^
"}" >> "%CSVFile%" 2>nul

echo [OK] Update status exported for %COMPUTERNAME%

endlocal
exit /b 0

What to look for in the fleet CSV:

  • Machines with pending CRITICAL updates: These need immediate patching because they're exposed to known vulnerabilities.
  • Machines with RebootRequired = Yes: Updates were downloaded/installed but the reboot was deferred. These machines are partially patched.
  • Machines with old LastCheckTime: The update service may not be running, or the machine hasn't connected to update servers recently.
  • Machines reporting ERROR: The Windows Update service may be broken. Run the cache reset script on these machines.

How to Avoid Common Errors

Wrong Way: Running usoclient Without Checking Services

:: MAY SILENTLY FAIL, if wuauserv is stopped, nothing happens
usoclient StartScan

usoclient does not report errors if the Windows Update service is not running. The command returns successfully but no scan occurs.

Correct Way: Verify and start the required services before triggering (Method 1).

Wrong Way: Expecting Console Output from usoclient

usoclient StartScan
:: (Waiting for output that never comes)
:: "Did it work? There's no output!"

usoclient produces NO console output, ever. All work happens in the background through the Windows Update service.

Correct Way: Use the PowerShell COM API (Methods 2–3) for scripts that need to know what happened. Use Settings → Windows Update for visual confirmation after usoclient.

Problem: Group Policy Blocks the Check

On managed networks (WSUS, SCCM, Intune), update scanning may be controlled centrally. usoclient StartScan and the COM API may be restricted.

Solution: Check with your IT department. On managed systems, updates are typically deployed through the management platform, not through local scripts.

Problem: Update Check Takes Too Long

The COM API's Search() method contacts Microsoft's update servers and can take 1–5 minutes depending on network speed and the number of updates to evaluate.

Solution: This is normal: the search is thorough. For scheduled scripts, run during off-hours. Method 4's fleet report handles this by running the search in the background.

Problem: Reboot Pending Prevents New Updates

If a reboot is pending from previous updates, new updates may not appear in the scan results until the reboot completes.

Solution: Method 1 checks the RebootRequired registry key and informs the administrator. Reboot to finalize pending updates before scanning for new ones.

Best Practices and Rules

1. Start Services Before Triggering

Always verify that wuauserv and bits are running before using usoclient or the COM API. Silent failures are the most common issue.

2. Use the COM API for Reporting

usoclient is for triggering. The COM API is for knowing. Use Method 2 to see what updates are available before deciding whether to install them.

3. Never Auto-Install on Production Servers

Method 3's automatic installation is convenient but dangerous on production systems. Use Method 2 to review available updates, test on non-production, then deploy manually or through change management.

4. Check for Pending Reboots

Pending reboots indicate partially installed updates. New updates may not appear or install correctly until the reboot completes.

5. Schedule Regular Status Collection

Run Method 4 weekly to maintain visibility into which machines need patching. Machines that fall behind on updates are the most vulnerable to security exploits.

6. Combine with Cache Reset for Stuck Updates

If the update check consistently fails or returns errors, the Windows Update cache may be corrupted. Run the cache reset script (clearing SoftwareDistribution and catroot2) before retrying.

Conclusion

Triggering Windows Update checks via Batch script ranges from simple fire-and-forget commands (usoclient StartScan) to comprehensive automation (COM API scan → download → install → reboot). For basic triggering, usoclient is sufficient. For reporting and decision-making, the PowerShell COM API provides the detail needed to manage updates responsibly. For fleet management, centralized status collection ensures no machine falls behind on critical security patches. Always verify services are running before triggering, and never auto-install on production systems without testing.