Deep-Dive: Automating Windows Updates Remediation Using Microsoft Intune with Azure Automation

Author: Ofir Gavish

Introduction

Automating Windows Updates Remediation for Devices with errors on Intune Expedited Update reports transforms reactive manual tasks into a proactive security model. This article provides an in-depth technical exploration of building this automation using Azure Automation, Microsoft Graph API and Microsoft Intune.

Understanding Microsoft Graph API

Initially, utilizing the Microsoft Graph API for device status retrieval appeared straightforward. However, specifying custom Intune policy names in the API calls produced confusing errors. Upon inspection, it became clear that the API requires specific built-in report identifiers like QualityUpdateDeviceStatusByPolicy rather than user-defined names.

Report Generation Workflow

To fetch reports from Intune via Graph API, an asynchronous workflow is mandatory:

  1. Initiate Report Generation: Using an HTTP POST request to trigger the creation of the report.
  2. Polling Status: Continuously checking the status via HTTP GET until the status transitions from notStarted to completed.
  3. Downloading the Report: Upon completion, a downloadable ZIP file is provided, containing the JSON report.

Example POST Request:

POST https://graph.microsoft.com/beta/deviceManagement/reports/exportJobs
{
    "reportName": "QualityUpdateDeviceStatusByPolicy",
    "filter": "(PolicyId eq 'YOUR_POLICY_ID')",
    "format": "json"
}

Polling Example:

do {
    $jobStatus = Invoke-MgGraphRequest -Uri $statusUri
    Start-Sleep -Seconds 5
} until ($jobStatus.status -eq "completed")

Technical Details: Parsing JSON Reports

The downloaded ZIP contains JSON with detailed device statuses. Parsing this JSON accurately is crucial:

$reportData = Get-Content "Report.json" | ConvertFrom-Json
$devicesWithErrors = $reportData | Where-Object { $_.CurrentDeviceUpdateStatus -eq "Error" }

foreach ($device in $devicesWithErrors) {
    Write-Host "Device: $($device.DeviceName), Error: $($device.LatestAlertMessage)"
}

Dynamic Management of Azure AD Groups

Devices identified with errors are dynamically added to Azure AD groups, facilitating targeted remediation. Here's how devices are programmatically added:

New-MgGroupMember -GroupId $group.Id -DirectoryObjectId $device.AzureAdDeviceId

Additionally, devices that report a successful update status in subsequent checks are automatically removed from the Azure AD assignment group. This ensures the remediation process is precise, targeting only those devices still requiring attention!

Integrating Microsoft GitHub Repo Functions to Deploy Platform Scripts via Intune

To simplify managing Intune scripts, functions from Microsoft's official GitHub repository were integrated, providing standardized, reliable methods for creating, updating, and assigning scripts:

# Example: Deploy a new script
New-MgDeviceManagementScript -BodyParameter $scriptParams

# Example: Update existing script
Update-MgDeviceManagementScript -DeviceManagementScriptId $scriptId -BodyParameter $scriptParams

# Example: Assign script to a group
New-MgDeviceManagementScriptAssignment -DeviceManagementScriptId $scriptId -BodyParameter $assignmentParams

Deploying Remediation Scripts via Intune

Intune expects scripts in Base64 encoding to ensure accurate transmission and storage, preserving the integrity of the content across different systems. The Base64 encoding process converts the script's text into ASCII text, safe for transmission over networks and reliably decoded by Intune on endpoints.

Example of encoding a script in PowerShell:

$scriptText = Get-Content -Path "RemediationScript.ps1" -Raw
$scriptContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($scriptText))

What the Remediation Script Does on the Endpoint

The PowerShell remediation script deployed through Intune is designed to intelligently check for common blockers that cause Windows updates to fail or get stuck. It first inspects the system for pending reboots, which can prevent update installation from completing successfully. This is done by checking known registry keys such as:

If a pending reboot is detected, the script schedules a system restart during a low-usage time (e.g., 2 AM). This proactive approach helps avoid user disruption while ensuring the system can move forward with the update process.

If no reboot is required, the script attempts to resolve other update-related issues by resetting the Windows Update components. This involves:

This script is fully self-healing and silent. It logs its operations to

C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\ExpeditedUpdateRemediation.log
for traceability and auditing. This ensures that admins can verify its activity and effectiveness without requiring user input or manual checking.

Automating Across All Policies

The script was further enhanced to iterate through all available expedited update policies, ensuring comprehensive coverage:

$policies = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/deviceManagement/windowsQualityUpdateProfiles"
foreach ($policy in $policies.value) {
    # Execute report generation and remediation for each policy
}

Full Script

The full script can be found in my GitHub Repo here

Conclusion

This deep-dive demonstrates building robust automation through detailed Graph API interactions, JSON parsing, dynamic group management, and proactive remediation. By thoroughly addressing these technical complexities, we've significantly enhanced operational efficiency and security resilience.