PatchDayAlert
Field Note · 9 min read · 1,743 words By Colten Anderson

Close the gap between your declared policy and what the box is actually running

A one-off registry edit closes a ticket and never makes it back into the GPO. Here's the three-surface audit that catches the drift, plus the one decision that actually closes the loop.

Close the gap between your declared policy and what the box is actually running

A print driver won’t load until SMB signing is flipped back off, so you flip it back off with a registry edit, the driver loads, the ticket closes. The change lives on that one host. It is not in the GPO. It is not in the Intune profile. Nothing in that workflow asked you to write it back, and six months from now it’s the value on one machine that nobody can explain.

That is the whole problem in one sentence: the baseline (a GPO, an Intune profile, a golden image) and the live state of a running machine are two separate things, and once they split, nothing in the normal workflow pulls them back together. NIST SP 800-128 built its security-focused configuration-management discipline around this split, because unmonitored systems drift on their own. Martin Fowler named the endpoint version of the failure the “snowflake server,” a box with enough undocumented tweaks that it can no longer be rebuilt from the declared build.

Microsoft’s own tooling shows which direction the gap runs. Config Refresh periodically reapplies assigned policy to Windows 11 devices precisely because local edits drift them between check-ins, and the documented way to make a manual fix stick is to run Pause Config Refresh first, for up to 24 hours, to stop Intune from overwriting it. Reconciliation runs one way only: baseline overwrites device. Pushing your local fix back up into the baseline is a separate, manual, easily-skipped step. When the pause lapses, the fix is either silently reverted or it survives as an exception the next Per setting status report can’t account for.

Who this affects

Domain-joined Windows endpoints under Group Policy. Windows 11 devices managed by Intune/MDM. Anything under Desired State Configuration. Non-domain machines count too; you check those with local-policy tooling instead of RSoP. If you own the change window, you own the drift.

How to check, on all three surfaces

Every surface has a built-in desired-versus-actual comparison. The trick is that “declared” and “actual” come from different commands, and the diff between them is the drift.

SurfaceDeclared baselineLive / applied stateThe diff
Group PolicyGet-GPOReportgpresult /h, Get-GPResultantSetOfPolicysecedit /analyze, Policy Analyzer
Intune / MDMexported profile JSONPer setting status, Get-Mg…DeviceStatusper-setting Success / Error / Conflict
Registry / stateDSC config, baseline.regTest-DscConfiguration, current.regResourcesNotInDesiredState, Compare-Object

Group Policy

gpresult and Get-GPResultantSetOfPolicy compute what a machine actually applied. Get-GPOReport dumps what the GPO declares. For security settings, secedit /analyze diffs the live system against a stored template.

# What this machine actually applied (RSoP), as HTML.
gpresult /h C:\rsop-actual.html          # needs elevation for computer settings

# What the GPO declares.
Get-GPOReport -Name "Endpoint Baseline" -ReportType Html -Path C:\gpo-declared.html

# Security policy: snapshot the current state, then diff live state against it.
secedit /export /cfg C:\baseline.inf
secedit /analyze /db C:\analysis.sdb /cfg C:\baseline.inf /log C:\analysis.log

secedit /analyze writes every mismatch to the log at C:\analysis.log; lines flagged as a mismatch are your drift. (secedit /export captures the template.) The graphical rsop.msc snap-in shows the same applied state interactively if you’d rather click.

For a purpose-built comparison, Policy Analyzer in the Security Compliance Toolkit captures a baseline, snapshots later state, and exports the delta to Excel, with LGPO.exe handling the local-policy leg so non-domain machines get checked the same way. LGPO.exe’s exact command-line switches aren’t on the Learn page, so drive it from its own help rather than from flags you half-remember.

Intune / MDM

Intune reports per setting, not just per policy. The Per setting status report (Devices > Configuration > policy > Per setting status) shows Success / Error / Conflict / Pending for each individual setting on each device. The same data is queryable via Graph.

# Per-device config status via the Graph SDK.
# Needs DeviceManagementConfiguration.Read.All.
Get-MgDeviceManagementDeviceConfigurationDeviceStatus -DeviceConfigurationId <id>

A Conflict on a setting is drift with a name: two policies fighting over one value. (Get-MgDeviceManagementDeviceConfigurationDeviceStatus is the SDK call.)

Registry and general state

Test-DscConfiguration is the canonical detection call. It reports without changing anything.

# Detection only. Applies nothing.
Test-DscConfiguration -ComputerName "Server01" -Detailed

# Manual single-key diff when you don't have a DSC resource for it.
reg export HKLM\Software\MyCo baseline.reg
Compare-Object (Get-Content baseline.reg) (Get-Content current.reg)

Test-DscConfiguration -Detailed returns InDesiredState plus ResourcesInDesiredState and ResourcesNotInDesiredState; the second list is your drift. The reg export plus Compare-Object fallback is plain PowerShell, not a reg.exe feature. To ask the same question across a fleet, osquery’s registry table makes registry state a SQL query.

If you run Ansible or Puppet, the audit-only pass is ansible-playbook site.yml --check --diff (check mode) and puppet agent --test --noop --show_diff (agent man page).

Closing the loop

Detection is worthless without a baseline to reconcile against, and that baseline has to live somewhere reviewable. For Group Policy, run Backup-GPO -All on a schedule and commit it to git; Microsoft’s BaselineManagement module converts those backups into DSC configs. For Intune, export profiles to JSON (IntuneManagement) and check the JSON into a repo. For DSC, the config is already code. Desired state is a reviewable artifact, not a click in a console.

The scheduled scan is where the enforce-versus-audit call gets made. The LCM’s ConfigurationMode takes three values: ApplyOnly (apply once, ignore drift), ApplyAndMonitor (the default: apply, then only log discrepancies), and ApplyAndAutoCorrect (apply, log, and re-push desired state), re-checked on ConfigurationModeFrequencyMins, default 15 minutes. Intune Remediations offer the identical fork: a detection-only script, or a detection script paired with a remediation that fires only on exit code 1. Rule of thumb: audit-only for anything with blast radius (auth, network policy), auto-correct for low-risk settings where the drift itself is the risk.

The tools already ship in the box. The missing piece is the rule that a delta is never allowed to just sit there.

Neither mode closes the loop on its own. That is a governance step. NIST SP 800-128 frames a baseline as changeable only through change control, which leaves exactly two legitimate outcomes when a scan surfaces a delta: revert the device to match the baseline, or promote the change into the baseline through change control and redeploy so every machine converges. A fix that is neither reverted nor promoted is an undocumented exception, which is the drift the scan exists to catch in the first place.

Revert-or-promote decision for detected config drift When a drift scan surfaces a delta, revert the device to baseline if the change is not a needed fix; otherwise promote the change into the version-controlled baseline through change control and redeploy so the fleet converges. drift scan surfaces a delta is the change a legitimate, still- needed fix? revert the device to baseline (enforce mode re-pushes) promote it: update the baseline in version control through change control, then redeploy no yes
Revert-or-promote logic per NIST SP 800-128 change control.

What drift costs

Security regressions are the most direct cost and usually invisible until something breaks. CIS Control 4 states the mechanism plainly: even a strong initial configuration “must be continually managed to avoid degrading security” as software is patched and configurations are “‘tweaked’ to allow the installation of new software or to support new operational requirements.” The GPO or Intune baseline still reports compliant while the live host quietly isn’t.

That divergence resurfaces at audit time. PCI DSS v4.0.1 Requirement 1.2.7 mandates review of network security control configurations at least every six months, and drift found between reviews is a direct finding. That requirement is specifically about network controls and firewalls, so read it as evidence of how auditors treat config drift, not as a claim that PCI mandates endpoint-registry review. HIPAA, ISO 27001, and CMMC configuration-management controls tend to follow the same structural pattern: auditors look for evidence that live systems match an approved baseline, not that a baseline document exists.

The starkest operational example is code-level rather than GPO-level, so take it as a parallel, not a match. In 2012 Knight Capital lost $440 million in 45 minutes because a deployment left one of eight trading servers running old code with a repurposed flag the rest of the fleet no longer carried; the SEC settled the resulting market-access violation for $12 million. One un-reconciled host, silently differing from baseline, found only when it broke.

Every command here runs in an afternoon. The rule they serve, revert it or promote it, never leave it, is the part that has to survive the next 2 a.m. outage, and that part isn’t a tool.

Sources

Share

Related field notes

Get the free CVE triage cheat sheet

Subscribe and we'll email you the one-page triage flow for fresh CVEs. Plus the weekly digest.

Subscribe