Using Intune Custom Compliance policies – how they work and how to discover installed software versions

A client I recently worked with wanted to make sure only compliant devices could access corporate resources. This is a fairly common request and implementation, but they also wanted a compliance policy to make sure certain security applications were installed. This post will look at how custom compliance policies work and show you how to use custom compliance policies to detect installed applications. We also look at how we can locate the version of the installed application so we can require a minimum or specific version.  

Custom compliance policies are unique and it’s important to understand how they work. We need two things to create a custom compliance policy. First, we need a PowerShell “discovery” script that gathers some kind of data from the target machines. In the below example we will start very simple by looking for a single installed application. The second component is a JSON file with the desired results. The PowerShell script will convert the output to JSON and those results get compared with the uploaded JSON file containing the desired results. If the values pass your rules, the device is marked as compliant. If not, the device will be marked as non-compliant.  

Let’s take a closer look at a PowerShell and JSON file, and see how they work to create a custom compliance policy. Below is a very simple script that looks to see if Chrome is installed. For more details on how to write your own custom compliance scripts and why the $hash variable is important, read https://learn.microsoft.com/en-us/mem/intune/protect/compliance-custom-script.  

$chrome = Get-Package -Name 'Google Chrome' -ErrorAction SilentlyContinue 
$chromeinstalled = $chrome.Name 
$hash = @{ Name = $chromeinstalled} 
return $hash | ConvertTo-Json -Compress 

Lets analyze this script and see what each line is doing:

  1. We are checking to see if the package “Google Chrome” is installed on the system. We add “-ErrorAction SilentlyContinue” so if it doesn’t exist, the script still runs and doesn’t return an error. The output is stored in the $chrome variable. So, running the top line on a machine looks like this: 
  1. Next, we have another variable that stores the Name field from the first $chrome variable. We can see the output here is Google Chrome. 
  1. Then we use the $hash variable to identify what the value of the “Name” is based on our previous variable. In this case, the variable $chromeinstalled, which is Google Chrome: 
  1. Lastly, we need to convert the $hash variable data to JSON, so it can be compared against the JSON file we upload in our compliance policy: 

Now lets look at a simple JSON file we can use with for PowerShell script we just reviewed. Its important that you read this article (https://learn.microsoft.com/en-us/mem/intune/protect/compliance-custom-json) and understand what is going on in the JSON file. Specifically, you should know what these lines do: 

  • SettingName - The name of the custom setting to use for base compliance. 
  • Operator - Represents a specific action that is used to build a compliance rule. For options, see the following list of supported operators
  • DataType - The type of data that you can use to build your compliance rule. For options, see the following list of supported DataTypes
  • Operand - Represent the values that the operator works on. 
  • MoreInfoURL - A URL that’s shown to device users so they can learn more about the compliance requirement when their device is noncompliant for a setting. You can also use this to link to instructions to help users bring their device into compliance for this setting. 
  • RemediationStrings - Information that gets displayed in the Company Portal when a device is noncompliant to a setting. This information is intended to help users understand the remediation options to bring a device to a compliant state. 

Here is our JSON file: 

{ 
"Rules":[ 
{  
       "SettingName":"Name", 
       "Operator":"IsEquals", 
       "DataType":"String", 
       "Operand":"Google Chrome", 
       "MoreInfoUrl":"https://smbtothecloud.com", 
       "RemediationStrings":[  
          {  
             "Language":"en_US", 
             "Title":"Chrome is not installed and must be installed for this device to be compliant", 
             "Description": "Chrome must be installed" 
          } 
       ] 
    } 
] 
} 

Let’s break the JSON down to see how it is used with our script output. If we look at the first four rule lines (SettingName, Operator, DataType, and Operand), they are looking for the output generated from out script. Below is our script output with the corresponding lines being compared to the JSON file. Its also important to have the correct operator and DataType. If your DataType and Operator are properly configured, and the values pass your rule, the device will be compliant.  

If we look at the bottom half of the JSON file, there is some other important information. The MoreInfo URL is the link for “How to Resolve This” in the company portal. The Title and Description give details as to why the device is not compliant as seen in the company portal app. Here is a snip of the company portal and the JSON file lines so you can see: 

Now hopefully you understand the relationship between the custom compliance policy script and the required JSON file. We will put this all together and create a custom compliance policy, only this time we will take it a step further and look for two values. We will check to see if Firefox is installed and if it meets a minimum version level of 107. 

Here is our PowerShell Script: 

$firefox = Get-Package -Name 'Mozilla Firefox (x64 en-US)' -ErrorAction SilentlyContinue 
$firefoxinstalled = $firefox.Name 
$firefoxversion = $firefox.Version 
$hash = @{ Name = $firefoxinstalled; Version = $firefoxversion} 
return $hash | ConvertTo-Json -Compress 

The output will show like below when the script runs on a system. You can see this machine is running Firefox version 105, so it should be marked as not compliant when we finish creating and applying this policy: 

Next, we need to create our JSON file with two rules. One that checks if Firefox is installed, and another to compare the number of the version output to be greater than or equal to 107. We also add a Title and Description for each rule to give details if the device fails the compliance check.  

{ 
    "Rules":[ 
    {  
           "SettingName":"Name", 
           "Operator":"IsEquals", 
           "DataType":"String", 
           "Operand":"Mozilla Firefox (x64 en-US)", 
           "MoreInfoUrl":"https://smbtothecloud.com", 
           "RemediationStrings":[  
              {  
                 "Language":"en_US", 
                 "Title":"Firefox is not installed and must be installed for this device to be compliant", 
                 "Description": "Firefox must be installed" 
              } 
           ] 
        }, 
    { 
      "SettingName":"Version", 
      "Operator":"GreaterEquals", 
      "DataType":"Version", 
      "Operand":"107.0", 
      "MoreInfoUrl":"https://smbtothecloud.com", 
      "RemediationStrings":[  
         {  
            "Language":"en_US", 
            "Title":"Firefox is running an outdated version and needs to be updated before this device will be marked as compliant", 
            "Description": "Update Firefox to version 107 or newer" 
         } 
      ] 
    } 
    ] 
    } 

Save your powershell script and json file, and go to the intune dashboard to create your custom compliance policy. Under Compliance Policies, select scripts to upload the PowerShell script. Provide a name and description and upload your script. 

Next, go back to compliance Policy, create a new policy for Windows 10 and later. Provide a name and description. Click next to move on to the compliance settings. Select require under custom compliance. Browse to the discovery script we uploaded in the previous step, and upload your json file we created earlier. If your JSON file is formatted properly, it will pull the setting names, operators, and values so you can see them.  

Click next and complete the actions for noncompliance, and assign to your target group. Once assigned, you can wait for the device to evaluate compliance, or you can force it to check with the company portal app.  

I used two test devices for this, one with the most recent version of Firefox installed, and another with version 105. We can see after the device with the older version evaluates compliance, it fails and is marked as not compliant with details in the company portal app: 

You probably won’t be writing custom compliance policies to check if Firefox is up-to-date, but it was an easy example to demonstrate how this works. Custom Compliance policies are a great tool to evaluate compliance when there is no pre-built template already available.