If you’re using Windows Update for Business in Microsoft Endpoint Manager you’re probably also using Microsoft’s Update Compliance solution for reporting. Update Compliance contains some useful data and I know the team are working on additional improvements.
A while back I created my own “Update Compliance” solution in part because I wasn’t happy with the data latency inherent in Microsoft Update Compliance, and in part because there was some additional data I wanted to report on, such as updates other than FUs and CUs like drivers as well as WU/WUfB policies and settings.
I wanted to publish some of the additional data that I gather with my solution so that, if you want to, you can add this data to same Log Analytics workspace where your Microsoft Update Compliance solution is installed and enhance your own reports.
To gather this data, deploy the PowerShell script below using Proactive remediations in Intune and run it on a schedule. The script supports full and delta inventories. The script will gather the data and send it directly to your Log Analytics workspace for ingestion into custom logs. This does require adding the workspace key to the script. Each log entry contains the Azure AD device Id, the Intune device Id and the computer name, so you can easily join the data with existing tables in Update Compliance.
Below is a summary of the data gathered. Some of this is now available natively in Update Compliance.
LA custom log name | Data |
---|---|
SU_DeviceInfo_CL | Inventory dates, OS info, manufacturer/model, current user, current patch level |
SU_AvailableUpdates_CL | Details on any updates available to a device on Windows update. This is gathered by scanning WU online. Updates are categorised. |
SU_UpdateLog_CL | Entries from the System event log and the Microsoft-Windows-WindowsUpdateClient provider. Includes only the most recent event per update. Updates are categorised. This is a handy source for quickly identifying which updates have attempted to install by WU, when, and whether they succeeded. |
SU_MDMUpdatePolicy_CL | Policy settings deployed for Windows Update for Business by Microsoft Endpoint Manager. Harvested from the registry at HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device\Update |
SU_WUPolicyState_CL | The current WU policy state. Harvested from the registry at HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UpdatePolicy\PolicyState |
SU_WUPolicySettings_CL | Indicates whether FUs or QUs are paused and the start and end times if they are. Harvested from the registry at HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UpdatePolicy\Setting and HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings |
SU_WUClientInfo_CL | Some general WU client info I find useful such as whether a reboot is pending from SUs, the WU service start-up type, whether AutoUpdate is enabled, if a reminder notification has been displayed and when, when a reboot may be scheduled for WUfB. |
SU_CompatMarkers_CL | Compatibility data for feature updates, eg whether an update is blocked, the “RedReason” (what’s blocking the update) and any safeguard hold Ids. |
To deploy the script, add your workspace ID and key, as well as a unique name, like your company name for example (this is used to create registry keys and a file directory). You can also set the minimum full and delta inventory schedules – these are a safeguard to prevent the script executing more frequently than needed because PR scripts can run multiple times in SYSTEM and user contexts.
The script will log to the registry at HKLM:\Software\<company name>\SoftwareUpdateReporting:

It will also create a local directory under C:\ProgramData\<company name>\SoftwareUpdateReporting containing the delta and full inventories in json format.

Just deploy the PR script as a detection script – no remediation script is required. You set the schedule, so you have as little or as much data latency as you want.
The script is available here.
Here are some example KQL queries on the data:
Query the current MDM Policy settings for a device:
SU_MDMUpdatePolicy_CL
| summarize arg_max(TimeGenerated,*) by IntuneDeviceID_g
| where ComputerName_s == "PC001"
Query all devices with failed driver updates:
SU_UpdateLog_CL
| where KeyWord2_s in ("Failure","Revert") and UpdateType_s == "Driver update"
| top-nested of IntuneDeviceID_g by temp=max(1),
top-nested 1 of InventoryDate_t by temp99=max(InventoryDate_t),
top-nested of ComputerName=ComputerName_s by temp1=max(1),
top-nested of UpdateName=UpdateName_s by temp2=max(1),
top-nested of KeyWord1=KeyWord1_s by temp3=max(1),
top-nested of KeyWord2=KeyWord2_s by temp4=max(1),
top-nested of RebootRequired=RebootRequired_s by temp5=max(1),
top-nested of UpdateType=UpdateType_s by temp6=max(1),
top-nested of WindowsVersion=WindowsVersion_s by temp7=max(1),
top-nested of WindowsDisplayVersion=WindowsDisplayVersion_s by temp8=max(1),
top-nested of KB=KB_s by temp9=max(1),
top-nested of ErrorCode=ErrorCode_s by temp10=max(1),
top-nested of ErrorDescription=ErrorDescription_s by temp11=max(1),
top-nested of EventTime=TimeCreated_t by temp12=max(1)
| project-away temp*

Query all Windows 10 devices that are blocked from upgrading to Windows 11:
SU_CompatMarkers_CL
| where CO21H2_BlockedFromUpgrade_s == "Yes" or CO21H2Setup_BlockedFromUpgrade_s == "Yes"
| summarize arg_max(TimeGenerated,*) by IntuneDeviceID_g
| project
TimeGenerated,
ComputerName_s,
CO21H2_BlockedFromUpgrade_s,
CO21H2_GatedBlockId_s,
CO21H2_RedReason_s,
CO21H2Setup_BlockedFromUpgrade_s,
CO21H2Setup_GatedBlockId_s,
CO21H2Setup_RedReason_s

My own UC solution has even more data than this as I also gather support info and update history from MS Docs and calculate compliance on a schedule using an Azure automation runbook, but that part is somewhat more complicated and not within scope of this post 🙂
Hopefully you will find this additional data useful, and you can also customise the script to add whatever other data you want to gather or inventory from your devices.