Microsoft has introduced client-driven compliance evaluation for Windows devices. The idea is simple. Instead of waiting for the next scheduled check-in, the device notices a change and asks Intune to check again.

So how does that work? The device has no new real-time compliance engine. A small part of the Intune Management Extension (IME) does all of that work: the compliance monitor. It monitors a short list of Windows settings, remembers what it saw last time, and when something changes, it starts a normal check-in. Intune then does what it always does: it evaluates the compliance policy.

The nice part is that you can follow the whole thing on the device itself. The IME writes every step to its log files, and it keeps its settings and the last values it saw in the registry. In this blog, we walk through the flow in ten steps, using the log lines and registry keys you can check yourself.

The short version: The device doesn’t decide whether it is compliant. It only decides when to ask for a check-in. Intune still does the evaluation. It notices changes in two ways: a timer (every 5 minutes by default) and event listeners for Windows Security Center, Defender, BitLocker, and a few registry values. Intune decides which compliance checks it monitors, and by default it asks for at most 2 check-ins per hour. Fixing the compliance issue triggers a check-in, just like breaking something does.

Why the device needs to detect the Compliance StateCopy Link

Most things in Intune start in the cloud. You change a policy, Intune sends a push, and the device checks in. Behind every push there is still a timer as a safety net, like the 8-hour MDM schedule.

Compliance doesn’t fit that model. When something changes on the device (Defender real-time protection is switched off, BitLocker is suspended, the firewall goes down), nothing can be pushed from the cloud. The cloud doesn’t know yet. Only the device knows.

Until the next scheduled check-in, Intune keeps showing the old compliance state, and Conditional Access keeps acting on it. It works the other way around too: a device that was fixed stays noncompliant until the schedule catches up. Client-driven compliance closes that gap by letting the device notice the change itself and ask for a check-in.

The Faster compliance updates for Windows devices OverviewCopy Link

This is the whole feature on one page. Intune sends the settings, the IME on the device notices, reads, compares, and decides, and the result is a normal check-in back to Intune. The numbers are the ten steps this blog walks through.

Figure 1 · Client-driven compliance: what lives in the cloud, what runs inside the IME, and how a change becomes a check-in.

What you will see in the Compliance Monitor logCopy Link

The compliance monitor writes to the IME log files in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs. Every part of it uses its own prefix, so it is easy to follow:

Log prefixWhat it does
[ComplianceMonitor]Starts the monitor, runs the timer and reads its settings
[EventSourceListener] / [EventSource]Starts and stops the event listeners and reports Event Log events
[ComplianceEventListener]Reports Security Center and registry changes
[ComplianceEventProcessor]Handles a batch of events and checks if something really changed
[ComplianceSettingHelper]Reads the current value of a setting
[DciHelper]The check-in gate: decides if the device asks for a check-in
[ComplianceMonitorStore]Saves settings and counters in the registry

The Real-time Faster Compliance flow in ten stepsCopy Link

Steps 1 to 3 happen when the monitor starts. Steps 4 to 10 repeat every time the timer runs or an event comes in. The numbers match the badges in the diagrams.

  1. The device must qualify. Windows 10 1703 or later, enrolled in Intune, Defender as the active antivirus.
  2. Intune sends the rules. One JSON value in the registry decides what is watched and how often.
  3. The monitor starts. It starts a timer and, where available, the event listeners.
  4. Something changes. An event comes in, or the timer runs.
  5. Read the real value. The monitor reads the current value from Windows.
  6. Compare with the last value. A different value is a change, in either direction.
  7. The gate decides. Already handled, observe-only, hourly limit reached, or go.
  8. The device asks for a check-in. A normal MDM session with one extra alert.
  9. Intune evaluates. Intune checks what the device reports and updates the state.
  10. Save and count. The new value is saved and the check-in is counted, only after success.

Steps 1–3: Getting the monitor runningCopy Link

Before reading a single value, three things must be in place: a qualifying device, the settings from Intune, and a running monitor.

Step 1: The device must qualifyCopy Link

Before the monitor does anything, it checks if this device is a candidate. Three things must be true. If one of them isn’t, the log tells you which one:

CheckWhat it meansLog line when it fails
Windows versionWindows 10 1703 (build 15063) or laternot applicable: OS build below Win10 1703.
MDM enrolledThe device is enrolled in Intune MDMnot applicable: device is not MDM-enrolled.
Defender activeMicrosoft Defender is the active antivirusnot applicable: Microsoft Defender is not the active AV.

That last one is worth knowing. If you use another antivirus and Defender runs in passive mode, the monitor doesn’t start at all.

Microsoft is also rolling the feature out in phases, so on some tenants the monitor simply doesn’t start yet. The IME tries again every hour. When the feature is turned on for you, the device picks it up without a restart:

Every hour the IME tries again to start the monitor (no-op when it is already running).

Step 2: Intune sends the Compliance rulesCopy Link

The monitor doesn’t decide what to watch. Intune does. The settings come along with the normal IME check-in and end up in the registry as one JSON value:

The monitor settings from Intune: ComplianceMonitorConfigJson under SessionSettings.

The monitor reads this value when it starts and again every round, so a change from Intune applies without a restart. It also keeps a copy under …\IntuneManagementExtension\ComplianceMonitor\Config. When the settings come in, you will see:

The settings from Intune came in. Here, all 14 settings are turned on.

The monitor’s own copy lives under …\ComplianceMonitor\Config, with the timer interval, the hourly limit, and one PerSetting key for every setting it watches:

The monitor’s own copy of its settings under ComplianceMonitor\Config.

This is what the JSON looks like, with the knobs Intune can turn:

{
  "Enabled": true,
  "PollIntervalSeconds": 300,
  "DciMaxCheckInsPerHourPerDevice": 2,
  "ComplianceEventProcessorBatchTimeSeconds": 10,
  "ComplianceEventProcessorDelayTimeSeconds": 300,
  "Settings": [ "ActiveFirewallRequired", "RtpEnabled", "OsBuildVersion" ],
  "PerSetting": { "ActiveFirewallRequired": { "Enabled": true }, ... },
  "EventPerSetting": { "RtpEnabled": { "Enabled": true }, ... }
}
SettingWhat it doesRangeDefault
PollIntervalSecondsHow often the timer checks1 min – 1 h5 min
DciMaxCheckInsPerHourPerDeviceHow many check-ins the device may ask for per hour0 – 102
ComplianceEventProcessorBatchTimeSecondsHow long events are collected before they are handled1 – 60 s10 s
ComplianceEventProcessorDelayTimeSecondsHow long to wait between two event batches1 s – 1 h5 min
Settings + PerSettingWhich settings the timer checks––
EventPerSettingWhich settings may be handled through events––
Enabledfalse turns the monitor off––

If a value is outside its range, the monitor corrects it and logs it, for example:

[ComplianceMonitor] PollIntervalSeconds 10 clamped to 60 on read — possible registry tamper or stale write.

Step 3: The monitor startsCopy Link

With a device that qualifies and its settings in place, the monitor starts. It starts a timer with a random first tick, so not every device checks at the same second. It also starts the event listeners:

The monitor starts.

[EventSourceListener] Starting listener: sourceCount=7.

The event listeners are newer than the timer and are rolled out separately. If you don’t see the listener line, the device only uses the timer for now. That still works; it just reacts a bit slower.

Steps 4–6: Noticing a changeCopy Link

Two ways to notice, one way to confirm. The event listeners are the fast lane, the timer is the safety net, and both end with the same read and the same comparison.

Figure 3 · Steps 4–6: where the signals come from, how the monitor notices them, and how a change is confirmed.

Step 4: Something changesCopy Link

The timerCopy Link

Every 5 minutes (or whatever Intune set), the monitor runs one round. It reads its settings again and then reads every setting Intune turned on, up to 14. Only one round runs at a time. If a round is still busy when the next one is due, the new one is skipped:

[ComplianceMonitor] Cycle skipped — previous cycle still running.

The event listenersCopy Link

The timer is the safety net. The event listeners are the fast lane. They listen to seven sources, and each one shows up in the log with its own name when it starts:

[ComplianceEventListener] Windows Security Center listener started: source=wsc.general-change.

[EventSource] Event Log listener started: source=DefenderOperationalRtp,

    channel=Microsoft-Windows-Windows Defender/Operational.

[ComplianceEventListener] Registry listener started: source=registry.os-version-change, …

Source name in the logWhat it listens toSetting
wsc.general-changeWindows Security Center changesActiveFirewallRequired, AntivirusRequired
DefenderOperationalRtpDefender Operational log, events 5000 and 5001 (real-time protection on/off)RtpEnabled
BitLockerManagementEncryptionBitLocker Management log, events 768 and 770BitLockerEnabled
SecurityCenterDefenderServiceApplication log, SecurityCenter events 15 and 16 for Windows DefenderDefenderEnabled
registry.defender-version-changeHKLM\SOFTWARE\Microsoft\Windows Defender · InstallLocationDefenderVersion
registry.os-version-changeHKLM\…\Windows NT\CurrentVersion · CurrentBuild, UBROsBuildVersion
registry.secure-boot-changeHKLM\SYSTEM\…\SecureBoot\State · UEFISecureBootEnabledSecureBootEnabled

The other settings (TPM, code integrity, signatures and anti-spyware) don’t have an event. The timer picks those up.

Want to see it yourself? On a test device, change the UBR value under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion. That is exactly the value the OsBuildVersion registry listener watches, so the monitor picks up the change right away.

Changing UBR on a test device: an easy way to trigger an OsBuildVersion change.

Events are not handled one by one. The monitor collects them for 10 seconds, handles them together, and then waits 5 minutes before it handles the next batch. Events that come in while it waits are kept for the next batch. That way, a burst of Defender events doesn’t turn into a burst of check-ins.

The most important thing to understand: an event is only a hint. It tells the monitor which settings to look at now. The monitor still reads the real value and compares it, just like the timer does. A Defender event that doesn’t really change anything ends like this:

[ComplianceEventProcessor] Event batch processed without drift: settings=RtpEnabled.

Step 5: Read the real valueCopy Link

Whether it was the timer or an event, the monitor now reads the current value of each setting. Most values come from the MDM Bridge WMI provider, which is the same device status information Intune works with. So the monitor looks at roughly what Intune will look at.

SettingWhere the value comes from
ActiveFirewallRequiredFirewall status (MDM Bridge)
AntivirusRequired · AntivirusRequireCurrentSignatureAntivirus status and signature status (MDM Bridge)
AntiSpywareRequired · AntiSpywareRequireCurrentSignatureAnti-spyware status and signature status (MDM Bridge)
BitLockerEnabledEncryption status (MDM Bridge)
SecureBootEnabledSecure Boot state (MDM Bridge)
DefenderEnabled · DefenderVersion · SignatureOutOfDateDefender status: service, product version and signature age
RtpEnabledDefender real-time protection setting
CodeIntegrityEnabledDevice Guard code integrity status
TpmRequiredTPM enabled and activated
OsBuildVersionCurrentBuild and UBR from the registry, for example 26100.4652

These are the same fourteen names you will find as keys under …\ComplianceMonitor\Config\PerSetting:

The fourteen settings the monitor can watch.

If one reading fails, that is logged for that setting, and the other settings carry on.

Step 6: Compare with the last valueCopy Link

For every setting, the monitor remembers the last value it accepted. You can find it in the registry:

The last value the monitor accepted, per setting. Here: the Defender version.

Same value? Nothing happened. Different value? That is a change, which the log calls a drift, with the old and the new value. The direction doesn’t matter. Firewall off is a change. Firewall back on is a change too. That is what lets a device get back to compliant quickly, and not only fall out of it.

[ComplianceEventProcessor] Event batch confirmed drift: settings=RtpEnabled.

Steps 7–10: From change to compliance stateCopy Link

A change doesn’t go straight to Intune. It passes the check-in gate first. Only then does the device check in and save the new value.

Figure 4 · Steps 7–10: the gate, the check-in, the evaluation in Intune and the save on the device.

Step 7: The gate decidesCopy Link

The check-in gate logs as [DciHelper]. Before it lets a change through, it asks four questions:

  1. Already handled? The timer and an event can spot the same change. If the other one was faster, the change is simply ignored: “Ignoring stale drift snapshot because its baseline was already updated.”
  2. Observe only? In the first phase of the rollout, the gate only logs the change and saves the new value, but doesn’t ask for a check-in. You will see decision=Simulated.
Observe-only: the OsBuildVersion change is logged, but there is no check-in.
  • Hourly limit reached? By default, the device may ask for 2 check-ins per hour. When the limit is reached, the gate waits and doesn’t save the new value yet. The next round finds the same change again and tries again once the hour is over. You will see decision=DeviceCapReachedDeferred.
Hourly limit reached: the firewall change has to wait.
  • Go. The device asks for a check-in (step 8).

One thing to keep in mind. The hourly counter is saved in the registry (…\ComplianceMonitor\Config\RateWindow), so it survives a restart. But when the IME starts and there is no recent counter, the gate plays it safe and starts the hour as if the limit was already reached. So right after an IME (re)start, the first hour can only wait:

[DciHelper] No persisted rate window found (first boot or registry missing); failing closed with cap=2

Step 8: The device asks for a check-inCopy Link

When the gate says go, the IME asks Windows to start a new MDM session, with one extra alert added to it:

Alert propertyValue
SourceIntuneRealTimeCompliance
TypeDriftRetry
TargetLocalDevice
DataRealTimeCompliance drift retry

From here, it is a normal check-in, with the same enrollment and the same kind of MDM session you get when you press Sync. If Windows doesn’t start the session within 30 seconds, the attempt counts as failed. Both outcomes are in the log:

The firewall change got through: the device asked for a check-in.

When Windows doesn’t start the session, you will see decision=TriggerFailed with an error code instead.

Step 9: Intune evaluatesCopy Link

This is why the monitor can stay so simple. It never tells Intune “compliant” or “not compliant”. It only makes sure the check-in happens now instead of later. During that check-in, the device reports its state, Intune checks it against the assigned compliance policies, and the admin center shows the result. Conditional Access follows from there.

When the setting changes back, the same thing happens the other way around.

Step 10: Save and countCopy Link

Only when the check-in started successfully does the gate save the new value as LastValue and count the check-in in the hourly counter. If the check-in failed or was held back, nothing is saved. The next round sees the same change again and tries again.

The hourly counter lives next to the settings. Count is the number of check-ins in the current hour, and WindowStartTicks is when that hour started, in UTC ticks. The PowerShell snippet at the end of this blog turns it into a readable time.

The hourly counter: one check-in so far in this hour.

What Faster Compliance (Client-Driven) does not doCopy Link

  • It doesn’t decide compliance on the device or send a verdict. Intune still evaluates.
  • It doesn’t watch every compliance setting. There are 14 settings, and 8 of them have an event.
  • It doesn’t ignore the hourly limit. A setting that keeps flipping can’t cause endless check-ins.
  • It doesn’t run when Defender isn’t the active antivirus, or when the device isn’t enrolled in Intune MDM.
  • It doesn’t promise real time. The observe-only phase, the hourly limit, the first hour after an IME start, the timer interval and the event batch can all hold a check-in back.

Before and afterCopy Link

Side by side, the difference is the gap between “the device changed” and “Intune knows”. Without client-driven compliance, that gap is the time until the next scheduled check-in. With it, the gap is the time to notice, a short batch and one check-in.

Figure 5 · How long Intune shows the old state, with and without client-driven compliance (not to scale).

How to check it on your own deviceCopy Link

Run these from an elevated PowerShell session. If a read is denied, run it as SYSTEM.

The settings Intune sentCopy Link

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\ComplianceMonitor\Config' |
Select-Object Enabled, PollIntervalSeconds, DciMaxCheckInsPerHourPerDevice, ComplianceEventProcessorBatchTimeSeconds, ComplianceEventProcessorDelayTimeSeconds, Settings, EventSettings

The last values it sawCopy Link

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\ComplianceMonitor\Settings' |
ForEach-Object { [pscustomobject]@{Setting   = $_.PSChildName LastValue = (Get-ItemProperty $_.PSPath).LastValue } }

The hourly counterCopy Link

$rw = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\ComplianceMonitor\Config\RateWindow'
[pscustomobject]@{HourStartedUtc = [datetime]::new([long]$rw.WindowStartTicks, 'Utc') CheckIns = $rw.Count }

The log linesCopy Link

Select-String -Path "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\*.log" `
-Pattern '\[(ComplianceMonitor|DciHelper|ComplianceEventProcessor|ComplianceEventListener|EventSourceListener)\]'
Log line containsWhat it tells you
not applicable: …Step 1: the device doesn’t qualify (Windows version, enrollment or Defender)
launcher armed (interval 60 min)Step 1: the IME will try to start the monitor every hour
ingested server config; settings=NStep 2: the settings from Intune came in
Poll interval changed Xs -> YsStep 2: Intune changed the timer interval
Start entered.Step 3: the monitor started
Starting listener: sourceCount=7Step 3: the event listeners started
Cycle skipped — previous cycle still runningStep 4: the previous round was still busy
Event batch confirmed drift: settings=…Step 6: an event led to a real change
Event batch processed without driftStep 6: an event, but nothing really changed
Ignoring stale drift snapshotStep 7: the change was already handled
decision=SimulatedStep 7: observe-only, no check-in
decision=DeviceCapReachedDeferredStep 7: hourly limit reached, tried again later
decision=Invoked … corrId=…Steps 8–10: check-in started, value saved
decision=TriggerFailed … errorCode=…Step 8: check-in failed, tried again next round

Wrapping upCopy Link

Faster compliance (Client-Driven) closes the gap where only the device knows that something changed. It does that without moving the compliance decision to the device. The IME watches a short list of settings, compares them with what it saw last time, and when something really changed, it asks for a normal check-in so Intune can do what it already does.

The event listeners make it fast: Security Center, Defender, BitLocker, and the registry. But an event is still only a hint. The value is always read again, always compared with the last value, and always passes the same gate with its hourly limit. Fast where it can be, careful where it has to be.