Intune

How to Create a Custom Compliance Policy in Intune

Published 18 March 2026 · 8 min read

Custom compliance policies in Intune let you check any device setting that is not covered by the built-in compliance options. You write a PowerShell detection script, define the rules to evaluate the output, and Intune marks devices compliant or non-compliant based on the result. This guide walks through building a complete custom compliance policy from script to Conditional Access enforcement.

How custom compliance works

The flow is straightforward:

  1. You write a PowerShell script that checks settings and outputs a JSON object
  2. You upload the script to Intune and define rules against its output values
  3. Intune runs the script on each device and evaluates the rules
  4. Devices that fail any rule are marked non-compliant
💡
What can you check?
Anything PowerShell can read - registry keys, file existence, service state, installed software, hardware specs, custom app settings, certificate presence, firewall rules, and more. If Get-* can retrieve it, you can compliance-check it.

Write the detection script

The script must output a JSON object to stdout using return (not Write-Output). Each key becomes a setting you can create a rule against.

# Custom Compliance Detection Script
# Returns JSON with device settings for Intune to evaluate

$result = @{}

# Check 1: Minimum OS build
$result["OSBuild"] = [System.Environment]::OSVersion.Version.Build

# Check 2: BitLocker status on C:
$blStatus = Get-BitLockerVolume -MountPoint "C:" -ErrorAction SilentlyContinue
$result["BitLockerEnabled"] = ($blStatus.ProtectionStatus -eq "On")

# Check 3: Windows Defender real-time protection
$defenderStatus = Get-MpComputerStatus -ErrorAction SilentlyContinue
$result["DefenderRealTimeEnabled"] = ($defenderStatus.RealTimeProtectionEnabled -eq $true)

# Check 4: Screen lock timeout (in seconds from registry)
$lockTimeout = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "InactivityTimeoutSecs" -ErrorAction SilentlyContinue).InactivityTimeoutSecs
$result["ScreenLockTimeoutSecs"] = if ($lockTimeout) { [int]$lockTimeout } else { 0 }

return $result | ConvertTo-Json -Compress
⚠️
Use return, not Write-Output
Intune reads the script output from the return value. Using Write-Output or Write-Host will cause the JSON parsing to fail. Always use return with ConvertTo-Json.

Create the custom compliance policy

Devices → Compliance → + Create policy → Windows 10 and later → Custom Compliance
  1. Click + Add under Detection script
  2. Upload your .ps1 detection script
  3. Move to the Compliance settings tab
  4. Define rules for each setting your script returns

Define compliance rules

For each key your script returns, you can create a rule. The operator options depend on the data type:

📋
Example rules for the script above
OSBuildMinimum Windows 10 22H2 build number
Greater than or equal to 19045
BitLockerEnabledDevice must have BitLocker on C: enabled
Equals True
DefenderRealTimeEnabledDefender real-time protection must be on
Equals True
ScreenLockTimeoutSecsScreen must lock within 15 minutes (900s)
Less than or equal to 900

Assign and monitor

Assign the policy to device or user groups as with any compliance policy. Monitor results under Devices > Compliance > select policy > Device status.

Devices that fail custom compliance rules show as non-compliant in the same view as built-in compliance failures, and feed into Conditional Access just the same.

More useful examples

Check if a specific application is installed

$result = @{}
$app = Get-CimInstance -ClassName Win32_Product | Where-Object { $_.Name -like "*CrowdStrike*" }
$result["CrowdStrikeInstalled"] = ($null -ne $app)
return $result | ConvertTo-Json -Compress

Check TPM version

$result = @{}
$tpm = Get-Tpm -ErrorAction SilentlyContinue
$result["TPMVersion"] = if ($tpm.TpmPresent) { "2.0" } else { "none" }
return $result | ConvertTo-Json -Compress

Frequently Asked Questions

Q: What is a custom compliance policy in Intune?

A custom compliance policy lets you write a PowerShell detection script that checks any setting on a device and returns a JSON result. Intune evaluates the JSON against rules you define and marks the device compliant or non-compliant based on the result. This extends built-in compliance checks with anything you can script.

Q: What does the detection script return?

The script must output a single JSON object where each key is a setting name and the value is the current value on the device. For example: {"DiskEncrypted": true, "OSVersion": "10.0.19045"}. Intune compares these values against the rules you define in the compliance policy.

Q: Can I use custom compliance policies with Conditional Access?

Yes. Custom compliance policies feed into the overall device compliance state. If a device fails a custom compliance check, it is marked non-compliant and Conditional Access policies that require compliant devices will block access.

Q: How often does the custom compliance script run?

The detection script runs on the same schedule as compliance evaluation - by default every 8 hours, and immediately when the device checks in. You can trigger a manual compliance check from the Intune portal or by running: Start-Process "C:\Program Files\Microsoft Intune Management Extension\Microsoft.Management.Services.IntuneWindowsAgent.exe"

Related Guides
-> Deploy PowerShell Scripts-> Enable BitLocker-> Cyber Essentials Setup
// need intune set up properly?
Fixed-price Intune setup for UK businesses

I set up Intune for UK small businesses at a fixed price - app deployment, compliance policies, Conditional Access, and full documentation.

View Packages