Force Windows Update on Intune Managed Windows 11 Devices

A common and frustrating challenge for Intune administrators: your policies are set, but devices remain out-of-date because the local Windows Update Service is stuck or corrupted. These Intune devices not updating pose a significant security risk, forcing IT staff into manual troubleshooting

INTUNEM365

11/21/20259 min read

white concrete building during daytime
white concrete building during daytime

Introduction - Solving the Intune Update Compliance Gap

Are you constantly battling devices that refuse to install the latest security patches, leaving you with lapsed Windows 11 compliance?

This is a common and frustrating challenge for Intune administrators: your policies are set, but devices remain out-of-date because the local Windows Update Service is stuck or corrupted. These Intune devices not updating pose a significant security risk, forcing IT staff into manual troubleshooting.

The Solution: Intune Proactive Remediations

The solution lies in leveraging Intune Proactive Remediations —now simply called Remediations—to automatically detect, reset, and force the update process without manual intervention.

In this guide, we provide a robust detection and remediation script package designed to target devices pending a reboot or stuck in a non-compliant state

Our script package will safely and effectively:

  • Detect a pending update or required reboot using multiple, comprehensive registry checks

  • Force the installation using the modern usoclient ScanInstallWait command

  • Schedule a graceful reboot with a 30-minute user notification to ensure data is saved

Follow this step-by-step guide to implement this crucial PowerShell script solution and regain control over your fleet's update status

Solution Overview: How the Proactive Remediation Package Works

This solution uses a pair of PowerShell scripts—a Detection Script and a Remediation Script—deployed via Intune Proactive Remediations. The goal is to enforce security updates and complete necessary reboots on non-compliant devices.

The Mechanism
  • Detection (Detect.ps1): The script runs and checks for multiple indicators of an incomplete update or pending reboot. If any key is found (like the Windows Update RebootRequired key or PendingFileRenameOperations), the script returns an Exit Code 1 (Non-Compliant), which triggers the remediation

  • Remediation (Remediation.ps1): This script executes only if the device is detected as non-compliant. It first attempts to ensure the Windows Update Service (wuauserv) is running. It then uses the usoclient ScanInstallWait command to initiate a combined scan, download, and installation of updates. Finally, it initiates a graceful 30-minute reboot if the updates require it

The scripts are designed to automatically detect and fix devices that are pending a reboot after updates.

Deep Dive: The Detection Script (Detect.ps1)

The detection script is the gatekeeper of this solution. Its sole job is to determine if a device requires an action (a forced update/reboot) and signal this by exiting with a non-zero code.

The Detection Logic: Exit Code 1

For Proactive Remediations, an Exit Code 1 (or any non-zero value) returned by the detection script means the device is Non-Compliant, triggering the remediation script. An Exit Code 0 means the device is Compliant, and no action is taken.

Our script employs a comprehensive check across three critical registry locations, ensuring that we catch pending actions from various system components and installers, not just the Windows Update service:

  1. Windows Update Required Key ($WURebootRequired):

    • Path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired

    • Purpose: This is the general indicator set by the Windows Update process itself

  2. Component-Based Servicing ($CBSRebootPending):

    • Path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending

    • Purpose: This specifically indicates a required reboot tied to the Servicing Stack or a Cumulative Update installation

  3. Pending File Rename Operations ($PFROPending):

    • Path: HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations

    • Purpose: This is the most robust check. Various installers (Microsoft Office, third-party software, Windows components) use this location to queue files that must be replaced after the next reboot. Its existence is a strong, universal indicator that a restart is needed to complete file operations

If any of these three checks return $true, the Test-PendingReboot function returns $true, and the script exits with Exit Code 1, triggering the powerful remediation script

The Detection Script (Detect.ps1) Content

PowerShell

# Detection Script: Check for All Pending Reboot Flags

# Exit 1 = Non-Compliant (Remediation will run)

# Exit 0 = Compliant (No remediation needed)

$global:ExitCode = 0

function Test-PendingReboot {

    # 1. Windows Update - Auto Update RebootRequired Key

    $WURebootRequired = Test-Path -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'

    # 2. Component-Based Servicing (CBS) - For servicing stack/cumulative updates

    $CBSRebootPending = Test-Path -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending'

    # 3. Session Manager - Pending File Rename Operations (a strong indicator from various installers)

    $PFRORegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'

    try {

        # Check if the PendingFileRenameOperations value exists AND is not empty

        $PFRO = (Get-ItemProperty -Path $PFRORegistryPath -Name 'PendingFileRenameOperations' -ErrorAction Stop).PendingFileRenameOperations

        if ($PFRO -ne $null -and $PFRO.Length -gt 0) {

            $PFROPending = $true

        } else {

            $PFROPending = $false

        }

    } catch {

        # If the key/value doesn't exist, Get-ItemProperty will throw an error, which is fine (not pending).

        $PFROPending = $false

    }

   

    # Report the highest priority issue found

    if ($WURebootRequired -or $CBSRebootPending -or $PFROPending) {

        Write-Host "Detection: Pending reboot detected. WUKey: $WURebootRequired, CBSKey: $CBSRebootPending, PFRO: $PFROPending. Remediation is required."

        return $true

    }

   

    Write-Host "Detection: No critical pending reboot detected."

    return $false

}

if (Test-PendingReboot) {

    $global:ExitCode = 1

}

exit $global:ExitCode

Deep Dive: The Remediation Script (Remediation.ps1)

The Remediation Script is responsible for taking corrective action, but it is engineered with several best practices to ensure minimal disruption while guaranteeing the required updates are installed.

Key Steps and Safety Features

The script executes three primary functions: logging, forcing the update, and ensuring a graceful reboot.

  1. Robust Logging (For Troubleshooting) The script establishes logging to three destinations, which is excellent for audit and troubleshooting:

    • A local log file ($env:TEMP\Intune_Remediation_Force_Update.log).

    • The Windows Event Log (Application Log) using a custom source (Intune-ProactiveRemediation-WU).

    • The PowerShell host, which is reported back to the Intune console.

  2. Forcing the Update Process The script first confirms the Windows Update Service (wuauserv) is running. The core of the action is the command: usoclient ScanInstallWait This is the modern, recommended method to tell the Update Orchestrator Service (USOClient) to perform a combined scan, download, and install cycle in a single operation.

    Post-Install Compliance Check and Wait After the USOClient process completes, the script enters a wait loop (up to 10 minutes). It continuously checks if the $RebootRequiredPath key has been removed. This loop is critical because it confirms the installation phase is truly finished before deciding whether a reboot is necessary.

  3. Graceful Reboot and User Notification (The Crucial Safety Measure) If the reboot key is still present after the wait loop, a critical update is assumed to be pending, and the script prioritizes user safety.

    • Immediate Message: It first sends an immediate, persistent console message using the msg * command. This provides immediate visibility to the user.

    • Delayed Reboot: It then schedules a graceful shutdown using shutdown /r /t 1800 (1800 seconds = 30 minutes). This provides the end-user with a countdown and a mandatory window to save their work, preventing sudden data loss.

    Compliance Flag Finally, the script sets a custom registry flag (HKLM:\Software\Company\Compliance\UpdateRemediated). This flag is an excellent method for using dynamic groups or custom compliance policies in the future to confirm when a device was last remediated.

The Remediation Script (Remediation.ps1) Content

# Remediation Script: Force Windows Update Scan, Install, and Graceful Reboot

# --- Logging Setup ---

$LogPath = "$env:TEMP\Intune_Remediation_Force_Update.log"

$EventSource = "Intune-ProactiveRemediation-WU"

# Ensure the custom event source exists (needed for security log entry, runs only once)

if (-not ([System.Diagnostics.EventLog]::SourceExists($EventSource))) {

    New-EventLog -LogName Application -Source $EventSource -ErrorAction SilentlyContinue | Out-Null

}

function Write-Log {

    param([string]$Message, [string]$Level = "INFO")

    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    $LogLine = "[$Timestamp] [$Level] $Message"

   

    # 1. Write to the local log file

    Add-Content -Path $LogPath -Value $LogLine

   

    # 2. Write to the Windows Event Log (Application Log)

    $EntryType = "Information"

    $EventID = 1000 # Use a specific ID for filtering

    switch ($Level) {

        "WARN"  { $EntryType = "Warning"; $EventID = 2001 }

        "ERROR" { $EntryType = "Error"; $EventID = 3001 }

        "CRITICAL" { $EntryType = "Error"; $EventID = 4001 }

    }

   

    try {

        Write-EventLog -LogName Application -Source $EventSource -EntryType $EntryType -EventId $EventID -Message $LogLine

    } catch {

        # Catch errors if writing to the log fails, but don't stop the main script execution

        Write-Host "WARNING: Failed to write to the Windows Event Log. $($_.Exception.Message)"

    }

   

    # 3. Write to the PowerShell host for Intune reporting

    Write-Host $LogLine

}

Write-Log "--- Starting Windows Update Remediation Script ---"

# --- Variables ---

$RebootRequiredPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'

$MaxWaitMinutes = 10

$WaitIntervalSeconds = 60

# --- Start Windows Update Service (Same as before) ---

Write-Log "Attempting to ensure Windows Update Service (wuauserv) is running..."

# ... (rest of service check code) ...

try {

    Set-Service -Name wuauserv -StartupType Automatic -ErrorAction Stop

    Start-Service -Name wuauserv -ErrorAction Stop

    Write-Log "Service ensured to be running."

} catch {

    Write-Log "WARN: Service start failed or was already running. Error: $($_.Exception.Message)" "WARN"

}

# --- Trigger USOClient Scan and Install (Same as before) ---

Write-Log "Triggering combined scan, download, and install (ScanInstallWait)..."

# ... (rest of USOClient code) ...

try {

    $Process = Start-Process -FilePath "usoclient" -ArgumentList "ScanInstallWait" -Wait -PassThru -ErrorAction Stop

    Write-Log "USOClient ScanInstallWait initiated and completed its foreground process. Exit Code: $($Process.ExitCode)"

} catch {

    Write-Log "ERROR: Failed to run USOClient ScanInstallWait. Update may be blocked." "ERROR"

}

# --- Post-Install Compliance Check and Wait (Same as before) ---

Write-Log "Checking for pending reboot keys after update trigger. Waiting up to $MaxWaitMinutes minutes..."

$RebootStillPending = $true

$Attempts = 0

do {

    $Attempts++

    $RebootStillPending = Test-Path -Path $RebootRequiredPath

    if (-not $RebootStillPending) {

        Write-Log "SUCCESS: RebootRequired key removed after $Attempts attempts. Update process appears complete."

        break

    }

    if ($Attempts -lt ($MaxWaitMinutes * 60 / $WaitIntervalSeconds)) {

        Write-Log "RebootRequired key still present (Attempt $Attempts). Waiting $WaitIntervalSeconds seconds..."

        Start-Sleep -Seconds $WaitIntervalSeconds

    }

} while ($RebootStillPending -and ($Attempts -lt ($MaxWaitMinutes * 60 / $WaitIntervalSeconds)))

# --- Final Action: Reboot if required, or exit gracefully (with enhanced user notification) ---

if ($RebootStillPending -eq $true) {

    # 1. Send an immediate, persistent console message to the user

    Write-Log "Sending immediate console message to user." "CRITICAL"

    try {

        cmd /c "msg * /TIME:300 'CRITICAL UPDATE: Mandatory updates have been installed. Your device will restart in 30 minutes to complete the process. Please save all work now!'"

    } catch {

        Write-Log "WARN: Failed to send user message using MSG command. Error: $($_.Exception.Message)" "WARN"

    }

    # 2. Schedule the graceful 30-minute reboot (1800 seconds)

    $RebootDelaySeconds = 1800

    $RebootMessage = "CRITICAL UPDATE: Your device will restart in 30 minutes to complete mandatory updates. Please save your work now."

    Write-Log "Reboot is required. Initiating graceful shutdown /r /t $RebootDelaySeconds. The user will see a countdown." "CRITICAL"

   

    cmd /c "shutdown /r /t $RebootDelaySeconds /c '$RebootMessage'"

} else {

    Write-Log "No reboot is required based on the registry check. Exiting successfully."

}

# --- Compliance Flag (Same as before) ---

# ... (rest of compliance flag code) ...

try {

    New-Item -Path "HKLM:\Software\Company" -Name "Compliance" -Force | Out-Null

    Set-ItemProperty -Path "HKLM:\Software\Company\Compliance" -Name "UpdateRemediated" -Value "$(Get-Date -Format 'yyyyMMdd')"

    Write-Log "Compliance flag set in registry."

} catch {

    Write-Log "WARN: Failed to set compliance flag." "WARN"

Implementation Guide: Prerequisites and Group Setup

Before deploying the script package, you must ensure your tenant meets the necessary licensing requirements for Proactive Remediations and create the target device group.

  1. Licensing Attestation (Critical Requirement)

    • Using Proactive Remediations requires a Windows Enterprise or equivalent license (e.g., Windows Enterprise E3 or E5) for the end-users on the target devices.

    • You must confirm ownership of these licenses in the Intune Admin Center:

    • Go to Tenant administration > Connectors and tokens > Windows data.

    • Set the Windows license verification toggle to On.

    • Click Save.

    This action attests to your organisation owning the necessary licenses and enables the Remediations feature in your tenant

  2. Create the Target Device Group

    You need a device group to target the script package. This group can be populated manually (Assigned) or dynamically (Dynamic Device) based on criteria like OS version or time since last check-in.

    • In the Microsoft Intune admin center, navigate to Groups > New Group

    • Set the Group type to Security

    • Give the group a clear name, such as 'Out of Date Windows 11 devices'

    • Set the Membership type to Assigned (for manual addition) or Dynamic Device (for rule-based membership). For a proof of concept, Assigned may be simplest

    • Click Create to save the group

  3. Prepare the Scripts

    Ensure your two PowerShell files are ready for upload:

    • Detect.ps1: Contains the logic to check for the three pending reboot registry keys

    • Remediation.ps1: Contains the logic to run usoclient ScanInstallWait and initiate the graceful 30-minute reboot

Step-by-Step Script Deployment in Microsoft Intune

With your groups created and your scripts (Detect.ps1 and Remediation.ps1) ready, you can now upload and configure the solution in Intune.

  1. Create the Custom Script Package

    • Navigate to Devices > Scripts and remediations in the Intune Admin Center

    • Under the Remediations tab, click Create

    • On the Basics tab, complete the required information:

      Name: Force Windows Updates

      Description: (Enter a description)

      Publisher: (Your name or Company name, e.g., Kumonix)

      Version: 1

  2. Configure Script Settings

    This step is crucial for ensuring the scripts run correctly in the system context and with the correct environment

    • Move to the Settings tab

    • Detection script file: Upload the Detect.ps1 file7. The preview window will display its contents for confirmation

    • Remediation script file: Upload the Remediation.ps1 file. The preview will show its contents

    • Configure the three bottom options exactly as follows:

      Run this script using the logged-on credentials: No (Scripts must run as the System account to manage services and registry keys (like HKLM))

      Enforce script signature check: No (Unless you have signed your PowerShell scripts with a trusted certificate)

      Run script in 64-bit PowerShell: Yes (Recommended for all modern Windows system scripts to ensure compatibility)

  3. Assign the Package and Schedule

    • Click Next and apply any Scope tags you wish to use

    • Click Next again to reach the Assignments tab

    • Under Included groups, locate and select the target group you previously created (e.g., 'Out of Date Windows 11 devices')

    • Choose the desired Schedule (e.g., Daily is a good starting point for compliance fixes)

    • Click Next and review all settings on the Review + create tab

    • Click Create to finish the process

      The script will now begin checking your target devices according to the defined schedule

Results and Validation: Monitoring Success

Once your script package has been deployed, the final step is monitoring the results to confirm your solution is successfully enforcing compliance across the target devices.

  • Navigate to Devices > Scripts and remediations in the Intune Admin Center.

  • Select your script package (Force Windows Updates).

  • Review the Overview dashboard.

This Force Windows Update Intune Script package provides a robust, self-healing mechanism for a critical compliance issue.

If you are looking for further efficiencies, you could refine the targeting group by creating a Dynamic Device Group rule that leverages the UpdateRemediated custom registry flag set by the remediation script. This allows you to specifically target only those devices that have not been successfully remediated in the last 30 or 60 days, focusing your script's efforts where they are truly needed