This week is focused on the update status of Windows devices. More specifically, this week is focused on making sure that Windows devices can only be compliant when running the latest cumulative update. Within a device compliance policy, it was already possible to specify a specific Windows version. That, however, is a manual action. Over and over again. That can be achieved easier nowadays. A few months ago I wrote about working with custom compliance settings. That enables the ability to add custom scripting to device compliance policies. Custom scripting basically means that anything is possible. Including the check on the update status. This post will show how to leverage that functionality with a small custom script to check for the update status of the latest cumulative update. For a check like that, a daily verification is often enough.
Important: At the moment of writing custom settings for compliance is still in preview. Once it becomes generally available, it will be additional cost to the licensing options that include Microsoft Endpoint Manager or Intune.
Creating a PowerShell script to check for the update status
When looking at the configuration, the first action is to create a PowerShell script that will be used to check for the update status of the latest cumulative update for Windows. The idea, however, is not that the user will have no time to install the latest cumulative update. With that in mind, the idea is to give the user a period of time to install that latest update. The PowerShell script example below checks for the latest patch Tuesday and adds an offset of days that is used to provide the user with the install window. Based on the installation status of the latest cumulative update, the Windows device will return if it’s Up-to-date or Not up-to-date. That information is returned in a compressed single line JSON-format.
[datetime]$dtToday = [datetime]::NOW
$strCurrentMonth = $dtToday.Month.ToString()
$strCurrentYear = $dtToday.Year.ToString()
[datetime]$dtMonth = $strCurrentMonth + '/1/' + $strCurrentYear
while ($dtMonth.DayofWeek -ne 'Tuesday') {
$dtMonth = $dtMonth.AddDays(1)
}
$strPatchTuesday = $dtMonth.AddDays(7)
$intOffSet = 7
if ([datetime]::NOW -lt $strPatchTuesday -or [datetime]::NOW -ge $strPatchTuesday.AddDays($intOffSet)) {
$objUpdateSession = New-Object -ComObject Microsoft.Update.Session
$objUpdateSearcher = $objUpdateSession.CreateupdateSearcher()
$arrAvailableUpdates = @($objUpdateSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0").Updates)
$strAvailableCumulativeUpdates = $arrAvailableUpdates | Where-Object {$_.title -like "*cumulative*"}
if ($strAvailableCumulativeUpdates -eq $null) {
$strUpdateStatus = @{"Update status" = "Up-to-date"}
}
else {
$strUpdateStatus = @{"Update status" = "Not up-to-date"}
}
}
else {
$strUpdateStatus = @{"Update status" = "Up-to-date"}
}
return $strUpdateStatus | ConvertTo-Json -Compress
Note: The PowerShell script logics for determining the second Tuesday of the month are based on this example provided by Travis Roberts on his GitHub.
Once the PowerShell script is written, it can be added to Microsoft Intune. That action should be performed before the update status can be used in the device compliance policy. The following five steps walk through the process of adding that script.
- Open the Microsoft Endpoint Manager admin center portal and navigate to Endpoint security > Device compliance > Scripts
- On the Compliance policies | Scripts page, click Add > Windows 10 and later
- On the Basics page, specify a Name and optionaly a Description and Publisher and click Next
- On the Settings page (as shown in Figure 1), specify the following information and click Next
- Detection script: Copy the just written PowerShell script
- Run this script using the logged on credentials: Select No to run the PowerShell script in SYSTEM context
- Enforce script signature check: Select No to not perform a signature check on the PowerShell script
- Run script in 64 bit PowerShell Host: Select Yes to run the PowerShell script in 64-bit
- On the Review + create page, verify the configuration of the PowerShell script and click Create
Note: Once the PowerShell script is added, it can be editted via Microsoft Endpoint Manager admin center portal.
Creating JSON to verify the update status
Once the PowerShell script is written and added to Microsoft Intune, the second action is construct a JSON-file. That JSON-file can be used to define the update status information that the device compliance policy should verify. Including the acceptable values for that status information. It even contains the options to configure a message that will tell the user what to do when the device is not compliant with the specified update status. In this case, the JSON-file must verify the Update status that is returned via the PowerShell script. Besides that, the operand can be used to verify for Up-to-date or Not up-to-date status.
{
"Rules":[
{
"SettingName":"Update status",
"Operator":"IsEquals",
"DataType":"String",
"Operand":"Up-to-date",
"MoreInfoUrl":"https://petervanderwoude.nl",
"RemediationStrings":[
{
"Language":"en_US",
"Title":"Device must be running the latest cumulative update for Windows.",
"Description": "Please make sure that the latest cumulative update for Windows is installed."
}
]
}
]
}
Creating a device compliance policy with update status check
Once the JSON-file is constructed, the third and last action is to create and configure a device compliance policy. That policy can be used to verify if the Windows devices are running the latest cumulative update and if those devices comply with the company policies. That compliance information can be used for reporting purposes, but also for usage with Conditional Access to determine access to data and resources. The following nine steps walk through the process of creating a device compliance policy that includes (and focusses on) the custom compliance setting for the update status.
- Open the Microsoft Endpoint Manager admin center portal navigate to Endpoint security > Device compliance
- On the Compliance policies | Policies blade, click Create Policy to open the Create a policy page
- On the Create a policy page, select Windows 10 and later with Platform and click Create
- On the Basics page, provide a valid name for the device compliance policy and click Next
- On the Compliance settings page, navigate to the Custom Compliance section (as shown in Figure 2), provide the following information and click Next
- Custom compliance: Select Require to enable the custom compliance setting
- Select your discovery script: Select the just uploaded PowerShell script
- Upload and validate the JSON file with your custom compliance settings: Select the just constructed JSON file
- On the Actions for noncompliance page, leave the default configuration of Action on Mark device noncompliant with Schedule (days after noncompliance) on Immediately and click Next
- On the Scope tags page, configure the applicable scope tags and click Next
- On the Assignments page, configure the assignment by selecting the applicable group and click Next
- On the Review + create page, review the configuration and click Create
Note: Keep in mind that a device compliance policy only supports a single custom compliance setting. That means a single PowerShell script. For multiple settings, use single PowerShell script to detect multiple different settings.
Experiencing the results of the update status check
Now let’s end this post by having a look at the results of the custom compliance setting for the update status. That will show it integrates with the compliance state of the device. Below in Figure 3 is an example of the update status of the latest cumulative update, that was created throughout this post.
More information
For more information about custom settings for compliance, refer to the following docs.
Hi Peter,
Great post and great use of the service, I’ve been waiting for this functionality for some time now as will others I suspect!
You mention that in order to use custom compliance it won’t be included in the Intune license, is this just the Intune license it’s not included in or will it really be an add-on for something like M365 BP/E3/E5?
Hi Nathan,
The exact license requirement are not yet available.
Regards, Peter
Unfortunately this is typical Microsoft. After companies are heavily invested in Intune, they start making new features paid add-ons, even for those with E5 licenses. If I squint really hard, I could see where remote help might make sense, since you previously had to pay for TeamViewer or another product. But custom compliance? Come on.
Within a few years I think any useful new features will be paid add-ons, with the Intune licenses only covering the very basics.
Good news Pete! There are signs that it might be included. See also: https://techcommunity.microsoft.com/t5/microsoft-endpoint-manager-blog/microsoft-endpoint-manager-adds-management-and-compliance-checks/ba-p/2902346
Regards, Peter
Hi Peter,
You’ve already defined an offset of 7 days in the script to give the user time to update their device. What do you think about changing this offset to 0 and configure in the custom compliance policy to mark this device after 7 days?
That would be much more customisable right?
Hi Roy,
Yes, that’s also a good option. Many ways to achieve something similar 🙂
Regards, Peter
This is such a great use of a cool feature, but I fear there must be some reason why Microsoft is not offering update compliance (for cumulative updates) out of the box?
Hi JM,
There are downsides of this method, as mentioned in the post, that are related to how often the compliance is checked. For a Microsoft standard option, you could use the build numbers, but that would require a monthly adjustment to the information.
Regards, Peter
I’ve set this up in our environment and assigned it to a couple of test devices.
When checking the compliance, the compliance status is ‘not applicable’ – any idea why this might be?
They are Windows 10/11 devices.
Hi Hachmuss,
Often a simple restart would fix that with me.
Regards, Peter
Hello!
Does this script work for any localization? I mean, won`t it be a problem to evaluate a compliance for Spanish, Polish, Ukrainian Windows?
Thanks in advance!
Hi Niko,
I haven’t tried it, but I would think so. The main to to check is the Microsoft.Update.Session object.
Regards, Peter
Hi Peter,
Nice blog, great idea. Though I have an issue.
I configured this and followed your steps 1-on-1 with the intOffSet=7.
I then installed a Windows 11 x64 22H2 22621.1105 VM and disabled the Windows Update service to prevent if from updating. This VM did not update, but it’s saying it’s compliant:
“PreRemediationDetectScriptOutput”:”{\”Update status\”:\”Up-to-date\”}”
Do you have an idea why that is? That build is of January 10th.
Hi Coert,
When you disabled Windows Update, you also can’t check for the latest update available. That’s probably why you’re compliant.
Regards, Peter
Silly me 🙂 Thx for the quick reply.
Hello Peter,
Loved your explaination! However, when i tested this policy the device installed the update but needed the reboot to finish the update process but in ntune, device was always compliant (i guess as update was already installed). This is the problem we have been facing in our environment as user dont restart their systems.
Do you have idea how we can modify the script to detect the reboot status of updates as well ?
Thank you
Hi Rochit,
That requires some registry checking. Did you collect the different locations that contain potential reboot pending messages?
Regards, Peter
Hello Peter,
Thanks for making this post. I was testing the script on my workstation, and despite having installed the latest cumulative update (KB5034123) last week, the Available Updates array returns with the latest update. The Search method does return that the 2024-01 .NET Cumulative Update was installed, just not the one for Win11 22H2. I have no pending reboots.
Thoughts?
Hi CR,
My apologies, but I don’t completely understand the issue. Which version of Windows are you using, which updates are installed, and which updates is the script missing?
Regards, Peter
We have a similar problem, running Windows 10 Pro. Update KB5034275 which seems to be related to KB5033909 and also KB5033918. When you run the script it reports this .net update missing. When you run windows update nothing is listed. Computer has KB5033909 installed but when you try and install KB5033918 it says not applicable.
PS C:\temp> .\Compliance.ps1
Title : 2024-01 Cumulative Update for .NET Framework 3.5, 4.8 and 4.8.1 for Windows 10
Version 22H2 for x64 (KB5034275)
AutoSelectOnWebSites : True
BundledUpdates : System.__ComObject
CanRequireSource : False
Categories : System.__ComObject
Deadline :
DeltaCompressedContentAvailable : False
DeltaCompressedContentPreferred : True
Description : A security issue has been identified in a Microsoft software product that could
affect your system. You can help protect your system by installing this update from
Microsoft. For a complete listing of the issues that are included in this update,
see the associated Microsoft Knowledge Base article. After you install this update,
you may have to restart your system.
EulaAccepted : True
EulaText :
HandlerID :
Identity : System.__ComObject
Image :
InstallationBehavior : System.__ComObject
IsBeta : False
IsDownloaded : False
IsHidden : False
IsInstalled : False
IsMandatory : False
IsUninstallable : False
Languages : System.__ComObject
LastDeploymentChangeTime : 09/01/2024 00:00:00
MaxDownloadSize : 73477730
MinDownloadSize : 0
MoreInfoUrls : System.__ComObject
MsrcSeverity : Important
RecommendedCpuSpeed : 0
RecommendedHardDiskSpace : 0
RecommendedMemory : 0
ReleaseNotes :
SecurityBulletinIDs : System.__ComObject
SupersededUpdateIDs : System.__ComObject
SupportUrl : http://support.microsoft.com
Type : 1
UninstallationNotes : This software update can be removed by selecting View installed updates in the
Programs and Features Control Panel.
UninstallationBehavior : System.__ComObject
UninstallationSteps : System.__ComObject
KBArticleIDs : System.__ComObject
DeploymentAction : 1
DownloadPriority : 2
DownloadContents : System.__ComObject
RebootRequired : False
IsPresent : False
CveIDs : System.__ComObject
BrowseOnly : False
PerUser : False
AutoSelection : 0
AutoDownload : 0
C:\temp>expand _f:* windows10.0-kb5033918-x64-ndp481_6af6ff5ac78463775555a866d6c1dde9d9ec68ad.msu .
Microsoft (R) File Expansion Utility
Copyright (c) Microsoft Corporation. All rights reserved.
Can’t open input file: _f:*.
Adding .\WSUSSCAN.cab to Extraction Queue
Adding .\Windows10.0-KB5033918-x64-NDP481.cab to Extraction Queue
Adding .\Windows10.0-KB5033918-x64-NDP481-pkgProperties.txt to Extraction Queue
Adding .\Windows10.0-KB5033918-x64-NDP481.xml to Extraction Queue
Expanding Files ….
Expanding Files Complete …
4 files total.
C:\temp>dir
Volume in drive C is Windows
Volume Serial Number is 362B-AB44
Directory of C:\temp
31/01/2024 10:57 .
31/01/2024 10:57 ..
12/01/2024 08:20 5FF20F84-9F94-4C76-B92E-ECD95665BFB5
07/12/2023 02:13 467 Windows10.0-KB5033918-x64-NDP481-pkgProperties.txt
07/12/2023 02:12 67,662,802 Windows10.0-KB5033918-x64-NDP481.cab
07/12/2023 02:13 465 Windows10.0-KB5033918-x64-NDP481.xml
31/01/2024 10:55 67,820,777 windows10.0-kb5033918-x64-ndp481_6af6ff5ac78463775555a866d6c1dde9d9ec68ad.msu
07/12/2023 02:17 202,678 WSUSSCAN.cab
8 File(s) 135,691,398 bytes
3 Dir(s) 119,377,838,080 bytes free
C:\temp>DISM.exe /Online /Add-Package /PackagePath:Windows10.0-KB5033918-x64-NDP481.cab
Deployment Image Servicing and Management tool
Version: 10.0.19041.3636
Image Version: 10.0.19045.3930
Processing 1 of 1 – Adding package Package_for_DotNetRollup_481~31bf3856ad364e35~amd64~~10.0.9214.3
[==========================100.0%==========================]
Error: 0x800f081e
The specified package is not applicable to this image.
The DISM log file can be found at C:\windows\Logs\DISM\dism.log
Hi Mark,
It’s just relying on the WUA. The only thing you can look at is if you can better tune the search.
Regards, Peter
Hi Peter, it’s all good. Have done exactly that and just put an exclude on that KB for now until Microsoft release a patch that you can actually install!
Thank you for that update, Mark!
Regards, Peter