The Last Days of Custom Compliance Policies

This blog will show you the nice wonderful addition to Intune, called the Custom Compliance Policy. This blog will be updated along the way as it’s new and this blog is just describing my own first attempts with these custom compliance policies and my opinions!

With the custom compliance policy, it’s (should be?) way easier to measure compliance.

  1. The Custom Compliance policy
  2. The PowerShell Detection Script
  3. The JSON
  4. The Results
  5. Some important stuff
  6. Manually enforcing a Custom Compliance Check
  7. Scheduling the Custom Compliance Check
  8. Conclusion

1. The Custom Compliance Policy

I guess everybody read my blog about device health attestation (DHA) and how BitLocker is measured and how you could solve this issue.

But now with the new custom compliance policy options, we have another solution at our disposal. With the use of Custom Compliance Policies (for Windows) we now have the option to write a simple PowerShell detection script to (I guess that’s obvious about a detection script) detect any setting we want to detect.

For example, if services are running, if specific files exist, or if Bitlocker is enabled and configured the way we want it to be.

The Powershell Detection Script will “return” the output of the PowerShell script in a JSON format to Intune/Microsoft Endpoint Manager. In the Custom compliance policy, we also need to define a JSON file. This JSON file will be used by Intune and will be compared with the PowerShell script output it got.

This JSON file will also be used to provide the end-user with a message on how they could “remediate” those messages. Mmm… Detection… Remediation… That sounds familiar, doesn’t it?

So to set it up we need a PowerShell Script and a JSON file

Afbeelding met tekst

Automatisch gegenereerde beschrijving

2. The PowerShell Detection/Discovery script

Okay, let’s start with the PowerShell Discovery (in my opinion just the detection script). In the first part, I showed you some examples you can use with Custom Compliance Policies. In this blog, I will show you a simple script to monitor Bitlocker Compliance.

What settings do we need, when we want to Monitor our BitLocker compliance? Let’s check out what kind of settings we have. We can check out the BitLocker settings with this command: Get-Bitlockervolume

So looking at the picture, I guess the EncryptionPercentage and ProtectionStatus will be fine (for now)

Afbeelding met tekst

Automatisch gegenereerde beschrijving

So how do we know what Setting Name we are going to monitor and use? For an example, I am monitoring the Percentage and Protectionstatus for compliance

Afbeelding met tekst

Automatisch gegenereerde beschrijving

The only thing you need to do, when you want to check out the values we need for compliance monitoring is export the good values on a working device first!

For example, First I am exporting all the BitLocker information on an already BitLocker working and enabled device.

As I showed you at the beginning of the blog, you will need to return the PowerShell output in JSON format. To do so we only need to return the variable ($) and convert it to JSON (Convertto-JSON). Please make sure you are also using the -compress option to make sure the output results are returned in one line.

Let’s take a good view of all the settings first with the knowledge we know now.

But I guess we don’t want to monitor everything for compliance only a select few. So I am adjusting the get-bitlockervolume to only show us the encryption percentage and protectionstatus.

If you want to define your own SettingName you can do it this way

$BLinfo = Get-Bitlockervolume 
$hash = @{Percentage= $BLinfo.EncryptionPercentage; ProtectionStatus = $BLinfo.ProtectionStatus}
return $hash | ConvertTo-Json -Compress

If you want to “just” use the SettingName from the Bitlocker output itself, you could do it this way. But remember you will need to make sure your JSON SettingName fits the Settingname from the BitLocker output!

$BLinfo = Get-Bitlockervolume | select Encryptionpercentage, protectionstatus
return $blinfo  | ConvertTo-Json -Compress

Looking at the picture above… that is way better to read! Of course, you could also add the “encryptionmethod” if you want to make sure your devices are compliant to match the XtsAes.

As an example, you want to use XtsAes256 and get your device NOT compliant if they are encrypted with XtsAes128

So let’s create the required PowerShell script first

We can now simply create a new PowerShell script and copy-paste the contents in the detection script part.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

When saving the PowerShell script you will notice (with the use of fiddler) that the PowerShell script will be saved as a Base64 value Compliance Script in Graph

URI: “”

3. The JSON

Now we have the PowerShell script ready. We need to also configure the JSON file itself to import in Intune. Otherwise, Intune only has the returned values but nothing to compare it with…

Let’s take a look at the JSON File first

             "Title":"Bitlocker Hard Drive must be fully encrypted",
             "Description": " Bitlocker Hard Drive must be fully encrypted "
             "Language": "en_US",
             "Title": "Bitlocker protection must be enabled.",
             "Description": " Bitlocker protection must be enabled.","

You will notice some important “fields” in the JSON file:

SettingsName: The setting we noticed in the PowerShell output

Operand: the value we noticed in the PowerShell output after the setting name



Create a JSON file for custom compliance settings in Microsoft Intune | Microsoft Docs

So when creating the PowerShell script and getting the returned values, you will need to take a good look at which datatype you are using and how you are comparing it. For an example, I guess the Bitlocker Encryption Percentage needs to be equal (IsEquals) to 100 (Int64)

You could also configure some nice remediations messages to make sure your employee knows what broke and how to fix it (even when they probably don’t have the permissions to do so..)

“Title”: “Bitlocker Hard Drive must be fully encrypted”,

“Description”: ” Bitlocker Hard Drive must be fully encrypted “

When you have selected the right JSON file you will notice (with the use of fiddler) that the JSON file will also be saved as a Base64 device compliance policy script in Graph

URI: “”

4. The Results

I will divide this part up into 2 subparts

  1. The Results When it’s compliant
  2. The Results when It’s not-compliant

4.1 The Results when it’s compliant

The first time, I deployed the Compliance Policies.. all the devices were showing as “Not Applicable

The assignments were good, normally the “not applicable” error could also be due to Licensing issues. If you were following my tweets you know that there is a sort of warning when deploying these Custom Compliance policies

But for now, that is something you don’t have to think about….yet. The only thing you need to do is, reboot your device and after a while, they will get applicable.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

Like always you will also find this information in the IntuneManagementExtension Log. As shown below, you will notice the Percentage and the Protectectionstatus

4.2 The Results when it’s not compliant

But what happens when your device isn’t compliant anymore? Let’s find out for ourselves by disabling Bitlocker (I know.. I am running this as admin as a normal user isn’t allowed to do this)

Afbeelding met tekst

Automatisch gegenereerde beschrijving

So I pressed the Check Access button and waited….

Afbeelding met tekst

Automatisch gegenereerde beschrijving

That’s weird… It is still compliant, even the agentexecutor is telling us the last check was 07:47 (when I booted my device today)

Also the results in the report section of the SideCarPolicies Scripts


The results are telling us it is still good to go and it is showing is no weird error codes. I was expecting the protectionstatus to be set to zero!

Even rebooting the device or stopping/starting the Intune mgt service didn’t trigger anything?

5. Some Important stuff

Detection and remediation….. Detection and remediation…Scripts…. Scripts Ow wait.. then it will use the HealthScripts in the IMECache folder just like Proactive remediations!

Afbeelding met tekst

Automatisch gegenereerde beschrijving

Of course, like always the execution of the Health Script is also visible in your IntuneManagementExtension amnd agentexecutor logs

There are some rules we need to beware of!

  • Like I told you earlier… when deploying Custom policies, your devices need to reboot before something will happen!
  • When updating the existing/changing PowerShell script in your compliance policy, it can take up to eight hours before it works!
  • The discovery scripts are run each 8 hours… so does that mean your device can be compliant for 8 hours even when it’s not compliant? I guess you know the answer when looking back at the results!
  • You can manually check your device to see if it’s compliant, but there is no check to fetch the latest updated PowerShell scripts. I guess that means, creating a new compliance policy instead of changing an existing one?

To dig a little bit more into the “The discovery scripts are run each 8 hours” part. The server-side (Intune) will ask the detection script to be run on the device after 8 hours. When the device could not be reached it will try it at the next boot.

I tried manually syncing the device (from intune and the device itself), manually checking for compliance from the company app, restarting the Intune Mgt service, and launching the Enterprise MGT tasks but still nothing happened or changed.

6. Enforcing a Custom Compliance Check

Microsoft is telling us to have patience when a Non-Compliant needs to become Compliant again

So: “It can take up to eight hours before a non-compliant status for a device update to show compliance”

But did you know what could speed things up? The same trick you could use to speed up the Proactive Remediations results if you didn’t want to wait an hour (when configured) to check the results.

To resume:(when you didn’t read the blog above 🙂 ).

When you want to speed things up, you will need to remove the corresponding reg keys from the Compliance Policy from this registry key:


After deleting the key and stopping/starting the Intune Management Extension, the compliance detection script will be re-run. When looking at the Intune Management Extension log, you will notice the Protectionstatus is now set to zero!

As shown below, I broke my Bitlocker and because of that, my device isn’t compliant!! You can do the same when a device is not-compliant and you fixed it!

7. Scheduling the Custom Compliance Check

Like I described in part 6, you can speed things up manually when you deploy the Custom Compliance Policy and your device isn’t becoming compliant even when you fixed it! We can clean up that proactive remediation Script from the registry … uhh sorry Compliance Policy Script from the registry manually but why not do it automatically?

I am not telling you it’s a good idea to be used in production, but I just wanted to make sure my test device is compliant or not compliant when it needs to be

This is the script I used to clean up the Custom Compliance Script from the registry to speed things up. In this example I am searching for the SettingName: EncryptionPercentage and will fetch the proper Registry key we are going to delete

#String to search for
$searchstring = "EncryptionPercentage"

#Get registry Location of the PowerShell Detection script
$location = Get-ChildItem "C:\Windows\IMECache\HealthScripts" -Recurse | Select-String $searchstring -List | Select Path
$parent = Split-Path $location
$parentfolder = Split-Path $parent -Leaf
$reglocationexecution = "HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\SideCarPolicies\Scripts\execution\*\$parentfolder\"
$reglocationreports ="HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\SideCarPolicies\Scripts\Reports\*\$parentfolder\"

#Remove registry values  
Remove-Item -Path $reglocationreports -Recurse -force
Remove-Item -path $reglocationexecution -Recurse -force

#stop start service 
Get-Service -DisplayName "Microsoft Intune Management Extension" | Stop-Service 
Get-Service -DisplayName "Microsoft Intune Management Extension" | Start-Service 

But how are we going to make sure this script is going to be run each 15 minutes? That’s simple, create a PowerShell script to schedule the script above in an encoded command and deploy this PowerShell script in the Endpoint Manager.

Just copy-paste the above script on this website and encode it to the UTF-16LE character set!

Now we have the encoded command we can create a new PowerShell script as I have shown below. Of course, change the -encodedcommand to your own script

$repeat = (New-TimeSpan -Minutes 15)
$trigger = New-JobTrigger -Once -At (Get-Date).Date -RepeatIndefinitely -RepetitionInterval $repeat

$User = "SYSTEM"
Register-ScheduledTask -TaskName "Speeding Things up!" -Trigger $Trigger -User $User -Action $Action -Force 
Set-ScheduledTask -taskname "Speeding Things up!" -Settings $(New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries)


I love the idea… but my first experience with it wasn’t that great… it felt a little bit buggy. But after some time it was working.

But why….why, 8 hours before the detection script is relaunched? In my opinion, this is the main reason I am not going to use it as I want it to fail within a few minutes… not a workday! And combine that 8 hours with probably an additional license to use it??

Mmmm I really hope I can dig into it later on today to find a solution for this. Waiting 8 hours before the device could fail compliance is not my “thing”. But as it looks like it is using ProActive remediations to trigger this… I hope we can set the timer for ourselves in the near future!

Waiting 8 hours to trigger it? NoNo sir, not for me… create your own scheduler to check that custom compliance policy (Don’t use part 7 in production 😛 )

But don’t get me wrong, I totally love the idea of creating your own compliance policies… but for now, I am not filled with joy (yet?). I hope Microsoft will give us the possibility to change the scheduler on the server-side

Im Not Quite Sure GIFs - Get the best GIF on GIPHY

Leave a Reply

Your email address will not be published. Required fields are marked *

  +  37  =  44