Fix Windows Defender Configuration Drift with PowerShell · CloudEngineerHub
Detection & Remediation9 min read4 views
How to Remediate Windows Defender Configuration Drift with PowerShell
A check-then-change PowerShell pair that repairs Windows Defender drift item by item: real-time protection, MAPS reporting, and sample submission, via Intune.
C
CloudEngineerHub Team
Published: September 18, 2026· Last Updated: September 28, 2026·9 min read
Security baselines do not stay applied just because you published them once. Between
local administrator changes, "optimization" tools that tweak Defender settings to make a
laptop feel faster, and incomplete migrations that leave devices in a halfway state,
individual machines drift away from the configuration you approved. The settings that
drift most often are the quiet ones: cloud reporting turned down, sample submission set
to never, real-time protection toggled off where Tamper Protection is not standing guard.
Visual Walkthrough
Every reliable detection script follows this exact structure — copy it.
Decision TreeDetection Script Anatomy — The Exit-Code Contract5/5
Decision gate
Is the state healthy?
One question, one exit code — keep detection dumb and honest.
Healthy → exit 0
1
Test the condition
Single cmdlet or property read; no side effects, no output noise.
2
Exit 0, no output
Silence is the success contract — Intune treats it as compliant.
Unhealthy → exit 1
1
Emit one evidence line
Write the observed value — your future self reads the report.
2
Exit 1
Signals "needs remediation"; the paired fix script may now run.
3
Remediate idempotently
Fix script is safe to run repeatedly; no reboots without consent.
4
Exit 0 after fix
Next detection run proves remediation worked.
Detection Script Anatomy — The Exit-Code Contract. Gate: Is the state healthy? — Healthy → exit 0: Test the condition — Healthy → exit 0: Exit 0, no output — Unhealthy → exit 1: Emit one evidence line — Unhealthy → exit 1: Exit 1 — Unhealthy → exit 1: Remediate idempotently — Unhealthy → exit 1: Exit 0 after fix
C
CloudEngineerHub Team
Author
The CloudEngineerHub editorial team — Microsoft endpoint management and cloud engineers writing hands-on guides on Intune, Azure, Entra ID, Autopilot, Defender and PowerShell. Every article is reviewed against current Microsoft documentation.
This article gives you a detection and remediation pair for exactly that drift. The
detection script compares three local Defender preferences against a baseline you declare
in the script. The remediation repairs only the items that actually drifted, one by one,
with a read-back verification after each change and a per-item log line. Devices where a
change does not stick, because Tamper Protection or a policy conflict blocks it, exit
with a distinct code so they surface in reporting instead of silently flip-flopping.
One thing this package will not do is fight your own policy. Intune's endpoint security
policy is the authoritative channel for Defender configuration, and the article is
explicit about what that means for where the durable fix lives.
Symptoms
Your security baseline report shows inconsistent values for cloud protection settings across similar devices.
Sample submission is set to "never send" on devices that should send safe samples automatically.
Get-MpPreference shows DisableRealtimeMonitoring: True on devices where real-time protection should be on.
Devices behave as if a setting changed after a support visit or a local tool ran, with no change record anywhere.
The Windows Security app shows different cloud-delivered protection states on nominally identical hardware.
Possible Causes
Local administrators with rights
Anyone with local admin can call Set-MpPreference, and on devices where Tamper
Protection is off, the change simply applies. Well-meaning performance tuning is the
everyday version; malicious quieting of the engine is the dangerous one.
Third-party tooling
System "optimizers", game boosters, and some software vendors' installers adjust
Defender preferences to avoid perceived conflicts. Their changes persist after the tool
is gone unless something repairs them.
Incomplete third-party AV migration
After a migration, some devices keep leftover preferences from a tool that no longer
exists. Cloud reporting and sample submission are common casualties because migration
tooling disables them first.
Policy pushing the wrong values
If an Intune or Group Policy object delivers settings that contradict your standard, the
devices are not drifting; they are obeying. This script would then fight policy on every
run, which is why the article says clearly: fix the policy first.
Tamper Protection disabled
With Tamper Protection off, all of the above become easy. Its absence is both a cause
and an amplifier, and worth treating as its own finding.
Detection Script
The detection script is read-only, runs in seconds in 64-bit SYSTEM context, and compares
three local preferences against constants declared at the top of the file. Adjust those
constants to your standard; the pair only works when detection and remediation agree.
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Detection script: compares local Microsoft Defender preferences against
the expected security baseline. Read-only.
.NOTES
Intended for Intune Scripts and Remediations, 64-bit SYSTEM context.
Adjust the three $expected* variables to your organization's baseline
before assigning the package.
Exit 0 = all baseline items match.
Exit 1 = at least one baseline item has drifted.
Exit 2 = Defender platform cmdlets unavailable on this device.
Exit 3 = unexpected error.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'DefenderBaselineDetection.log'# ---- Baseline: adjust these three values to your security standard ----$expectedDisableRealtimeMonitoring = $false # real-time protection must be ON$expectedMapsReporting = 'Advanced' # MAPS cloud reporting level$expectedSubmitSamplesConsent = 1 # 1 = send safe samples automaticallyfunction Write-DetectionLog {
param([Parameter(Mandatory)][string] $Level, [Parameter(Mandatory)][string] $Message)
if (-not (Test-Path $logDir)) { New-Item -Path$logDir -ItemType Directory -Force | Out-Null }
"$([DateTime]::UtcNow.ToString('o')) [$Level] $Message" | Out-File -FilePath$logFile -Append -Encoding utf8
}
try {
Write-DetectionLog 'INFO''Defender baseline drift detection run started.'
Write-DetectionLog 'INFO'"Baseline: DisableRealtimeMonitoring=$expectedDisableRealtimeMonitoring MAPSReporting=$expectedMapsReporting SubmitSamplesConsent=$expectedSubmitSamplesConsent" # ---- Gate: Defender platform cmdlets must exist ----if (-not (Get-Command -Name'Get-MpPreference' -ErrorAction SilentlyContinue)) {
Write-DetectionLog 'WARN''Get-MpPreference is unavailable - the Defender platform is missing or this SKU does not include it.'
exit 2
}
$pref = Get-MpPreference
# ---- Item 1: real-time protection ----$actualRt = $pref.DisableRealtimeMonitoring
if ($actualRt -ne$expectedDisableRealtimeMonitoring) {
Write-DetectionLog 'ERROR'"Drift: DisableRealtimeMonitoring is $actualRt, expected $expectedDisableRealtimeMonitoring (real-time protection off)."
}
else {
Write-DetectionLog 'INFO'"OK: DisableRealtimeMonitoring is $actualRt."
}
# ---- Item 2: MAPS cloud reporting ----$actualMaps = [string]$pref.MAPSReporting
if ($actualMaps -ne$expectedMapsReporting) {
Write-DetectionLog 'ERROR'"Drift: MAPSReporting is $actualMaps, expected $expectedMapsReporting."
}
else {
Write-DetectionLog 'INFO'"OK: MAPSReporting is $actualMaps."
}
# ---- Item 3: sample submission consent ----$actualSamples = [int]$pref.SubmitSamplesConsent
if ($actualSamples -ne$expectedSubmitSamplesConsent) {
Write-DetectionLog 'ERROR'"Drift: SubmitSamplesConsent is $actualSamples, expected $expectedSubmitSamplesConsent (0=AlwaysPrompt 1=SendSafeSamplesAutomatically 2=NeverSend 3=SendAllSamplesAutomatically)."
}
else {
Write-DetectionLog 'INFO'"OK: SubmitSamplesConsent is $actualSamples."
}
if ($actualRt -ne$expectedDisableRealtimeMonitoring -or$actualMaps -ne$expectedMapsReporting -or$actualSamples -ne$expectedSubmitSamplesConsent) {
Write-DetectionLog 'INFO''Drift detected - remediation needed.'
exit 1
}
Write-DetectionLog 'INFO''All baseline items match - device compliant.'
exit 0
}
catch {
Write-DetectionLog 'ERROR'"Unexpected failure: $($_.Exception.Message)"
exit 3
}
finally {
Write-DetectionLog 'INFO''Defender baseline drift detection run finished.'
}
Detection Logic
Platform gate.Get-MpPreference must exist. A device without the Defender
platform exits 2; that state belongs to the antivirus-disabled detection package,
not this one.
Real-time protection.DisableRealtimeMonitoring must read $false. This is the
single most consequential drift item, and the only one Tamper Protection actively
guards; a True here is an ERROR line in the log.
Cloud reporting.MAPSReporting must read Advanced. Values read back as strings
(Disabled, Basic, Advanced) and are compared case-insensitively by PowerShell's
string equality.
Sample submission.SubmitSamplesConsent must read 1 (send safe samples
automatically). The mapping of the numeric values (0 = always prompt, 1 = safe samples
automatically, 2 = never send, 3 = all samples automatically) is written into the log
line so the finding is readable months later.
Aggregation. Any drifted item produces an ERROR line and the script exits 1.
Otherwise it exits 0 with all three OK lines in the log.
Remediation Script
The remediation reads the same three preferences and calls Set-MpPreference only for
items that differ from the baseline. After each set, it reads the value back and verifies;
a value that still reads drifted (Tamper Protection interference, or a policy that keeps
reapplying the wrong value) is recorded and drives a distinct exit code. The script
touches nothing else: no exclusions, no engine versions, no service manipulation, and it
never disables anything.
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Remediation script: restores drifted Microsoft Defender preferences to
the expected security baseline. Repairs ONLY the items that drifted,
check-then-change, with per-item logging and read-back verification.
.DESCRIPTION
Baseline items (adjust to your security standard, keeping the detection
script's constants identical):
- DisableRealtimeMonitoring = $false (real-time protection on)
- MAPSReporting = Advanced
- SubmitSamplesConsent = 1 (send safe samples automatically)
HONEST LIMITS:
- Tamper Protection, when enabled, may block or silently revert local
changes to protected Defender settings. If a value still reads
drifted after the set, the script exits 1 so the device surfaces in
reporting; the durable fix is correct Intune policy.
- Intune endpoint security policy is the authoritative channel. If
policy itself pushes the wrong values, this script fights it on
every run - fix the policy instead.
.NOTES
Exit 0 = baseline restored or already compliant.
Exit 1 = one or more values still drifted after the set attempt
(Intune reports this as an error, which is the intent).
Exit 2 = Defender platform cmdlets unavailable.
Exit 3 = unexpected error.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'DefenderBaselineRemediation.log'# ---- Baseline: keep identical to the detection script ----$expectedDisableRealtimeMonitoring = $false$expectedMapsReporting = 'Advanced'$expectedSubmitSamplesConsent = 1function Write-RemediationLog {
param([Parameter(Mandatory)][string] $Level, [Parameter(Mandatory)][string] $Message)
if (-not (Test-Path $logDir)) { New-Item -Path$logDir -ItemType Directory -Force | Out-Null }
"$([DateTime]::UtcNow.ToString('o')) [$Level] $Message" | Out-File -FilePath$logFile -Append -Encoding utf8
}
try {
Write-RemediationLog 'INFO''Defender baseline remediation run started.' # ---- Gate: Defender platform cmdlets must exist ----if (-not (Get-Command -Name'Get-MpPreference' -ErrorAction SilentlyContinue) -or -not (Get-Command -Name'Set-MpPreference' -ErrorAction SilentlyContinue)) {
Write-RemediationLog 'WARN''Defender cmdlets are unavailable - the platform is missing on this device.'
exit 2
}
$pref = Get-MpPreference
$changed = $false$failures = @()
# ---- Item 1: restore real-time protection ----if ($pref.DisableRealtimeMonitoring -ne$expectedDisableRealtimeMonitoring) {
Write-RemediationLog 'INFO'"Drift found: DisableRealtimeMonitoring=$($pref.DisableRealtimeMonitoring). Restoring real-time protection."
Set-MpPreference -DisableRealtimeMonitoring$expectedDisableRealtimeMonitoring -ErrorAction Stop
$changed = $true$check = (Get-MpPreference).DisableRealtimeMonitoring
if ($check -ne$expectedDisableRealtimeMonitoring) {
$failures += "DisableRealtimeMonitoring still reads $check after the set (Tamper Protection or a policy conflict may be blocking local changes)"
}
else {
Write-RemediationLog 'INFO''Restored: DisableRealtimeMonitoring now matches the baseline.'
}
}
else {
Write-RemediationLog 'INFO''OK: DisableRealtimeMonitoring already matches the baseline.'
}
# ---- Item 2: restore MAPS reporting level ----if ([string]$pref.MAPSReporting -ne$expectedMapsReporting) {
Write-RemediationLog 'INFO'"Drift found: MAPSReporting=$([string]$pref.MAPSReporting). Restoring to $expectedMapsReporting."
Set-MpPreference -MAPSReporting$expectedMapsReporting -ErrorAction Stop
$changed = $true$check = [string](Get-MpPreference).MAPSReporting
if ($check -ne$expectedMapsReporting) {
$failures += "MAPSReporting still reads $check after the set (Tamper Protection or a policy conflict may be blocking local changes)"
}
else {
Write-RemediationLog 'INFO'"Restored: MAPSReporting now reads $check."
}
}
else {
Write-RemediationLog 'INFO''OK: MAPSReporting already matches the baseline.'
}
# ---- Item 3: restore sample submission consent ----if ([int]$pref.SubmitSamplesConsent -ne$expectedSubmitSamplesConsent) {
Write-RemediationLog 'INFO'"Drift found: SubmitSamplesConsent=$([int]$pref.SubmitSamplesConsent). Restoring to $expectedSubmitSamplesConsent (send safe samples automatically)."
Set-MpPreference -SubmitSamplesConsent$expectedSubmitSamplesConsent -ErrorAction Stop
$changed = $true$check = [int](Get-MpPreference).SubmitSamplesConsent
if ($check -ne$expectedSubmitSamplesConsent) {
$failures += "SubmitSamplesConsent still reads $check after the set (Tamper Protection or a policy conflict may be blocking local changes)"
}
else {
Write-RemediationLog 'INFO'"Restored: SubmitSamplesConsent now reads $check."
}
}
else {
Write-RemediationLog 'INFO''OK: SubmitSamplesConsent already matches the baseline.'
}
if ($failures.Count -gt0) {
foreach ($failurein$failures) { Write-RemediationLog 'ERROR'"Not restored: $failure" }
Write-RemediationLog 'ERROR''One or more baseline items could not be restored locally. Fix the source policy in Intune; the device follows policy, not scripts.'
exit 1
}
if ($changed) { Write-RemediationLog 'INFO''Baseline restored.' }
else { Write-RemediationLog 'INFO''Device already compliant - no changes made.' }
exit 0
}
catch {
Write-RemediationLog 'ERROR'"Defender baseline remediation failed: $($_.Exception.Message)"
exit 3
}
finally {
Write-RemediationLog 'INFO''Defender baseline remediation run finished.'
}
The Tamper Protection caveat belongs here in full, because it changes how you read
results. When Tamper Protection is enabled, Windows blocks external changes to protected
Defender settings, and the blocked change can look like a silent no-op. That is the
platform defending your baseline, not the script failing: the read-back check catches it
and exit 1 puts the device in your queue. The durable fix for a device that will not
accept the local change is correct Intune endpoint security policy, because policy is the
channel the device obeys on every refresh. Fix the policy and the drift disappears; run
the script against a wrong policy and you have created a weekly tug-of-war.
Deploying Through Intune
Sign in to the Microsoft Intune admin center, go to Devices → Scripts and remediations, and select + Add on the Windows 10/11 tab.
On Basics, name it Remediate - Defender baseline drift and state the blast radius: "restores three Defender preferences (real-time protection, MAPS, sample submission); touches nothing else".
On Detection script, upload detect.ps1. On Remediation script, upload remediate.ps1. Set Run script in 64-bit PowerShell: Yes and Run this script using signed-on credentials: No on both.
Leave Enforce script signature check: No unless you sign internal scripts and deploy the certificates.
On Schedule, choose Daily. Drift repair is a maintenance loop, not an incident response; daily keeps exposure windows short without hammering the platform.
On Assignments, pilot with a group of test devices including one where you deliberately drifted a setting. Then target the Windows client group where this baseline applies. If different device groups have different baselines, deploy separate packages with their own constants rather than one script with conditionals.
Post-specific notes:
Keep the baseline constants identical in both scripts. A mismatch means detection and
remediation disagree forever, and every run churns.
If your tenant manages these settings through endpoint security antivirus policy,
reconcile that policy first. The script is for the gaps policy does not cover and the
devices that fall out of it.
Devices reporting exit 1 after a remediation run deserve a look at the log: the
read-back lines say whether Tamper Protection or a conflicting policy blocked the value.
Visual Walkthrough
What must be true before Defender policies can do their job.
Interactive FlowMDE Onboarding — Sensor to Attack Surface Control6/6
1
Licensing verified
MDE P1/P2 entitlements mapped to users (not devices).
deploy
2
Onboarding package via Intune
Configuration profile ships the onboarding blob.
telemetry
3
Sensor reports in
Endpoint sensor connects to MDE service; device visible in portal.
ASR, device control, firewall, web protection via Intune.
6
Attack surface shrinks
Alerts, TVM score and ASR blocks show measurable lift.
MDE Onboarding — Sensor to Attack Surface Control. 1. Licensing verified: MDE P1/P2 entitlements mapped to users (not devices). — 2. Onboarding package via Intune: Configuration profile ships the onboarding blob. — 3. Sensor reports in: Endpoint sensor connects to MDE service; device visible in portal. — 4. OS/platform updated: Defender platform + intelligence updated automatically. — 5. Policies flow: ASR, device control, firewall, web protection via Intune. — 6. Attack surface shrinks: Alerts, TVM score and ASR blocks show measurable lift.
Exit Codes
Code
Meaning
0
Detection: no drift. Remediation: baseline restored or already compliant
1
Detection: at least one baseline item drifted. Remediation: a value still reads drifted after the set attempt
2
Prerequisites: Defender platform cmdlets unavailable on this device
3
Unexpected script error - inspect the log
Intune evaluates the detection script first; any non-zero result triggers the remediation
per your schedule. A device flipping between "Remediated" and "Error" across runs is the
signature of a blocked setting: the log names the item every time.
Every line carries a UTC timestamp, a level, and one fact: a baseline declaration, an OK
per item, a drift finding with actual and expected values, a restore action, or a
read-back result. Because each item is logged separately, one glance tells you which of
the three settings a device lost and whether the repair stuck. Rotation at monthly
intervals is ample; the files grow by a handful of lines per day.
Troubleshooting the Script
Remediation exits 1 on the same devices every run. Read the read-back lines. If
the value reverts, check for conflicting endpoint security policy or a Tamper
Protection block; the script will not win that fight and should not.
Exit 3 mentioning a Set-MpPreference exception. Confirm the device's Defender
platform is intact and you are in 64-bit context; a corrupted platform fails writes
before Tamper Protection is even involved.
Detection exits 0 but the security console shows drift. You are looking at two
different baselines. Compare the constants in the script with the policy definition and
pick one source of truth.
MAPS value reads differently than expected. The property is an enum; the script
compares its name as a string. If your baseline is Basic, change the constant rather
than comparing numbers.
Nothing logs at all. The package did not run: check assignment scope, filter
evaluation, and the device's last check-in before debugging the script.
How to Validate the Fix
On a lab device, run detect.ps1 elevated. Expect exit 0 and three OK lines.
Drift one setting deliberately, for example set SubmitSamplesConsent to 2 with
Set-MpPreference, and re-run detection. Expect exit 1 naming that item.
Run the remediation manually. Expect exit 0 with the drift line, the restore line,
and the read-back confirmation for that item only.
In the admin center, confirm the device status shows Remediated after a sync, then
check the Windows Security app or Get-MpPreference by hand to see the restored value
outside the script's own view.
Production Considerations
Execution context. Both scripts run as SYSTEM in 64-bit Windows PowerShell. The
Defender preference writes require the elevation SYSTEM provides.
Idempotency. Check-then-change on every item: matching values are never re-set,
and repeated runs either do nothing or converge. Read-back verification makes each run
self-auditing.
Side effects and reboots. The changes take effect in the running engine without a
restart. Restoring sample submission means the device may begin uploading safe samples
again, which is the intended behavior of your baseline; confirm your privacy review
covers it.
Security review notes. No credentials or secrets are used, and the scripts neither
add exclusions nor weaken any protection; they only restore approved values. Review the
baseline constants with your security team, validate the package on a test ring with
your PowerShell automation SME, and confirm the Tamper Protection behavior on your
builds before broad production rollout.
What if Tamper Protection blocks the change?
Then the read-back check catches it and the script exits 1, surfacing the device in
Intune as an error. That is the honest outcome: the platform refused a local write to a
protected setting. The fix is correct endpoint security policy in Intune, which is the
channel the device obeys, not more aggressive local scripting.
Why are only three settings in the baseline?
Because they are the settings with the highest drift rate and the lowest repair risk.
Every additional setting widens the blast radius and multiplies the policy-conflict
surface. Extend the baseline deliberately, keeping detection and remediation constants
identical and adding read-back verification for each new item.
Why does the script compare SubmitSamplesConsent as a number?
The property is a numeric enumeration with documented values: 0 always prompts, 1 sends
safe samples automatically, 2 never sends, 3 sends all samples. Comparing the number and
writing the mapping into the log keeps the finding unambiguous for whoever reads it
later.
Comments
0No comments yet — be the first to share your thoughts.