Using update status as part of the compliance of Windows devices

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.

  1. Open the Microsoft Endpoint Manager admin center portal and navigate to Endpoint security > Device compliance > Scripts
  2. On the Compliance policies | Scripts page,  click Add > Windows 10 and later
  3. On the Basics page, specify a Name and optionaly a Description and Publisher and click Next
  4. 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
  1. 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.

  1. Open the Microsoft Endpoint Manager admin center portal navigate to Endpoint security Device compliance
  2. On the Compliance policies | Policies blade, click Create Policy to open the Create a policy page
  3. On the Create a policy page, select Windows 10 and later with Platform and click Create
  4. On the Basics page, provide a valid name for the device compliance policy and click Next
  5. 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
  1. 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
  2. On the Scope tags page, configure the applicable scope tags and click Next
  3. On the Assignments page, configure the assignment by selecting the applicable group and click Next
  4. 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.

23 thoughts on “Using update status as part of the compliance of Windows devices”

  1. 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?

    Reply
  2. 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.

    Reply
  3. 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?

    Reply
  4. 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?

    Reply
    • 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

      Reply
  5. 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.

    Reply
  6. 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!

    Reply
  7. 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.

    Reply
  8. 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

    Reply
  9. 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?

    Reply
    • 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

      Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.