Detect EDR and Antivirus Health Issues with PowerShell · CloudEngineerHub
Detection & Remediation9 min read4 views
Detecting EDR and Antivirus Health Issues with PowerShell
Detect Defender for Endpoint onboarding drift with PowerShell: Sense service state, onboarding registry markers, and antivirus running mode, with a safe local fix.
C
CloudEngineerHub Team
Published: September 7, 2026· Last Updated: September 28, 2026·9 min read
Microsoft Defender for Endpoint is the detection backbone of most modern Windows estates,
and its health is quietly load-bearing: when the Sense service is stopped, when onboarding
markers are missing, or when the antivirus runtime sits in a passive mode, the device keeps
working normally for users while producing no detections, no alerts, and no vulnerability
data. Because those failures are invisible from the login screen, they tend to surface
during an incident review, exactly when it is too late to matter.
Visual Walkthrough
The engine behind every “Detect with PowerShell” runbook on this site.
Exit 1 flips the device into the remediation queue for this package.
remediate
3
Remediation executes
Fix script runs silently as SYSTEM with a 5-minute budget.
verify
4
Re-run detection
The same detection script must now exit 0 — proof, not hope.
telemetry
5
Results report
Per-device outcome lands in Reports → Remediations for trend analysis.
6
Repeat on schedule
The loop continues — drift gets caught the day it appears.
Continuous cycle
Proactive Remediations — The Detect → Fix → Verify Loop. 1. Detection script runs: Scheduled (daily/hourly): exit 0 healthy, exit 1 unhealthy — nothing more. — 2. Verdict: unhealthy: Exit 1 flips the device into the remediation queue for this package. — 3. Remediation executes: Fix script runs silently as SYSTEM with a 5-minute budget. — 4. Re-run detection: The same detection script must now exit 0 — proof, not hope. — 5. Results report: Per-device outcome lands in Reports → Remediations for trend analysis. — 6. Repeat on schedule: The loop continues — drift gets caught the day it appears.
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 paired PowerShell detection and remediation set for EDR and
antivirus health on Intune-managed Windows devices. The detection script evaluates three
independent signals: the Sense service state, the onboarding markers under the Windows
Advanced Threat Protection registry key, and the Defender antivirus running mode from
Get-MpComputerStatus. The remediation script deliberately does one small thing well: it
repairs the local service when it is disabled or stopped. Everything policy-driven, such as
onboarding itself, is flagged for an Intune-side fix instead of being faked locally.
Both scripts follow the Intune Scripts and Remediations conventions used throughout this
series: 64-bit SYSTEM context, structured logging to C:\ProgramData\Company\Logs, and
honest exit codes that map cleanly to device status in the admin center.
Symptoms
EDR health problems are rarely reported by users. You will usually find them through
reports, or worse, during an investigation. The common signals are:
Devices missing from the Microsoft Defender portal's device inventory, or appearing with a stale "last seen" timestamp.
Sensor health reports in Defender showing devices as misconfigured, inactive, or partially onboarded.
The Sense service absent, stopped, or Disabled in services.msc on affected devices.
Get-MpComputerStatus reporting AMRunningMode values such as Passive Mode or SxS Passive Mode instead of Normal, or RealTimeProtectionEnabled set to False.
Security tasks in Intune flagging endpoint protection violations on devices that look otherwise compliant.
A useful pattern: a device that checks in to Intune perfectly but has not touched the
Defender portal in days almost always has a local agent problem, not a network problem.
Possible Causes
Onboarding policy never reached the device
Defender for Endpoint requires an onboarding configuration deployed through Intune, Group
Policy, or another supported method. If the policy is missing, mis-assigned, or filtered
out by scope tags, the device never receives its onboarding blob and the registry markers
never appear.
The Sense service was disabled or broken locally
Hardening scripts, third-party cleanup tools, and "debloat" packages sometimes disable
services they do not recognize. A Disabled Sense service produces a device that is
onboarded on paper but blind in practice.
Antivirus is in a passive mode
When a third-party antivirus is present, Defender can legitimately enter passive mode, and
Windows reports that state through AMRunningMode. Passive mode is sometimes intentional
during a migration, but it is a finding when your baseline says Defender should be the
primary antivirus.
Platform components damaged by an upgrade or image capture
Golden images that captured a half-onboarded state, or interrupted platform updates, can
leave the service registered but non-functional. These devices usually show the service
present but the antivirus runtime unreadable.
Detection Script
The script below is read-only and finishes in seconds. It checks the Sense service, the
Windows Advanced Threat Protection registry key (existence only, because value names vary
across builds), and the Defender antivirus running mode, and classifies the device with a
single exit code.
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
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Detection script: checks Microsoft Defender for Endpoint onboarding and
antivirus health signals on the local device.
.DESCRIPTION
Read-only. Collects:
1. The 'Sense' service (Microsoft Defender for Endpoint service):
presence, start mode, and running state.
2. Onboarding markers under
HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat Protection. The
script checks key existence only; individual value names vary across
platform builds, so no values are interpreted.
3. Antivirus status from Get-MpComputerStatus (AMRunningMode and
RealTimeProtectionEnabled).
Exit 0 = service running, onboarding markers present, AV mode healthy.
Exit 1 = service missing/disabled/stopped, the ATP registry key is absent,
or the AV is in a passive mode / real-time protection is off.
Exit 2 = antivirus runtime status could not be read (state unknown).
Exit 3 = unexpected error.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'EdrAvDetection.log'$senseServiceName = 'Sense'$atpKeyPath = 'HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat Protection'$onboardingInfoPath = 'HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat Protection\OnboardingInfo'function 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''EDR and antivirus health detection started.' # ---- Check 1: Sense service ----$service = Get-Service -Name$senseServiceName -ErrorAction SilentlyContinue
if ($null -eq$service) {
Write-DetectionLog 'ERROR'"Service '$senseServiceName' (Microsoft Defender for Endpoint) is not installed on this device."
exit 1
}
$serviceCim = Get-CimInstance -ClassName Win32_Service -Filter"Name='$senseServiceName'" -ErrorAction SilentlyContinue
$startMode = 'Unknown'if ($null -ne$serviceCim) { $startMode = $serviceCim.StartMode }
Write-DetectionLog 'INFO'"Sense service found. Status=$($service.Status) StartMode=$startMode"if ($startMode -eq'Disabled') {
Write-DetectionLog 'ERROR''Sense service is Disabled - the endpoint agent cannot run.'
exit 1
}
if ($service.Status -ne'Running') {
Write-DetectionLog 'ERROR'"Sense service is $($service.Status) (expected Running)."
exit 1
}
# ---- Check 2: onboarding markers (existence only) ----$atpKeyExists = Test-Path $atpKeyPath$onboardingInfoExists = Test-Path $onboardingInfoPath
Write-DetectionLog 'INFO'"Onboarding registry: key exists=$atpKeyExists OnboardingInfo subkey exists=$onboardingInfoExists"if (-not $atpKeyExists) {
Write-DetectionLog 'ERROR''The Windows Advanced Threat Protection registry key is absent - the agent has never onboarded. Onboarding is delivered by MDE policy, not by local registry edits.'
exit 1
}
if (-not $onboardingInfoExists) {
Write-DetectionLog 'WARN''OnboardingInfo subkey not found. Value layout varies by platform build, so this is advisory: verify onboarding status in the Defender portal before concluding a problem.'
}
# ---- Check 3: antivirus runtime status ----try {
$mpStatus = Get-MpComputerStatus -ErrorAction Stop
$runningMode = $mpStatus.AMRunningMode
$realTimeProtection = $mpStatus.RealTimeProtectionEnabled
$antivirusEnabled = $mpStatus.AntivirusEnabled
Write-DetectionLog 'INFO'"Antivirus status: AMRunningMode=$runningMode RealTimeProtectionEnabled=$realTimeProtection AntivirusEnabled=$antivirusEnabled"if ($runningMode -eq'Passive Mode' -or$runningMode -eq'SxS Passive Mode') {
Write-DetectionLog 'WARN'"Defender antivirus is in '$runningMode'. Expected during third-party AV migrations, but real-time protection is owned by another product - confirm this is intended."
exit 1
}
if ($realTimeProtection -eq$false) {
Write-DetectionLog 'ERROR''Real-time protection is disabled on an active Defender antivirus installation.'
exit 1
}
}
catch {
Write-DetectionLog 'WARN'"Get-MpComputerStatus failed: $($_.Exception.Message)"
Write-DetectionLog 'WARN''Antivirus runtime state is unknown on this build - treat the result as inconclusive.'
exit 2
}
Write-DetectionLog 'INFO''EDR service, onboarding markers, and antivirus status are healthy.'
exit 0
}
catch {
Write-DetectionLog 'ERROR'"Unexpected failure: $($_.Exception.Message)"
exit 3
}
finally {
Write-DetectionLog 'INFO''EDR and antivirus health detection finished.'
}
Detection Logic
The checks are ordered from most to least authoritative:
Sense service. The script reads presence, start mode, and running state through
Get-CimInstance rather than Get-Service alone, so a Disabled start type is caught even
while the service happens to be running. A missing Sense service with an otherwise
healthy device strongly suggests the MDE platform was never deployed.
Onboarding markers. The key HKLM:\SOFTWARE\Microsoft\Windows Advanced Threat
Protection must exist on an onboarded device. The script checks key existence and
deliberately does not interpret individual values, because value names and layout have
shifted across platform versions and interpreting them wrong would be worse than not
interpreting them at all.
Antivirus runtime. Get-MpComputerStatus supplies AMRunningMode and
RealTimeProtectionEnabled. Normal with real-time protection enabled is the healthy
baseline. Passive or SxS passive modes are reported as findings because the decision to
run a third-party antivirus belongs to policy, not to whatever got installed locally.
Classification. Any service failure, missing onboarding key, or unhealthy antivirus
mode returns exit 1. If the antivirus status cannot be read at all, the script exits 2
rather than guessing healthy.
Each check writes a line to C:\ProgramData\Company\Logs\EdrAvDetection.log, so the log
gives you the exact reason a device was flagged.
Remediation Script
The remediation is intentionally narrow: it sets the Sense service start type to Automatic
when Disabled, and starts it when stopped. It never writes onboarding or offboarding
blobs, never edits the Windows Advanced Threat Protection registry, and never touches
antivirus policy. Onboarding repairs are policy work, and the script says so rather than
pretending otherwise.
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
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Remediation script: repairs the local Microsoft Defender for Endpoint
service (Sense) when it is disabled or stopped.
.DESCRIPTION
Scope (deliberately narrow):
- Sets the Sense service start type to Automatic when it is Disabled.
- Starts the Sense service when it is not running and waits for it.
This script NEVER writes onboarding or offboarding blobs, never edits
Windows Advanced Threat Protection registry values, and never changes
antivirus policy. Full onboarding and offboarding repairs are policy-driven
(an MDE onboarding policy deployed through Intune) and cannot be done
safely by a local script.
Exit 0 = service already running, or repaired and running.
Exit 1 = service could not be brought to the Running state.
Exit 2 = Sense service not installed - MDE platform deployment is needed.
Exit 3 = unexpected error.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'EdrAvRemediation.log'$senseServiceName = 'Sense'function 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''EDR service remediation started.'$service = Get-Service -Name$senseServiceName -ErrorAction SilentlyContinue
if ($null -eq$service) {
Write-RemediationLog 'WARN'"Sense service not present. Deploy the Microsoft Defender for Endpoint platform and onboarding policy through Intune; nothing can be repaired locally."
exit 2
}
$changed = $false # ---- Enable the service when it is Disabled ----$serviceCim = Get-CimInstance -ClassName Win32_Service -Filter"Name='$senseServiceName'" -ErrorAction SilentlyContinue
$startMode = 'Unknown'if ($null -ne$serviceCim) { $startMode = $serviceCim.StartMode }
if ($startMode -eq'Disabled') {
Set-Service -Name$senseServiceName -StartupType Automatic
Write-RemediationLog 'INFO''Sense service was Disabled - set startup type to Automatic.'$changed = $true
}
# ---- Start the service when it is not running ----if ($service.Status -ne'Running') {
Write-RemediationLog 'INFO'"Starting Sense service (previous status: $($service.Status))."
Start-Service -Name$senseServiceName -ErrorAction Stop
$service.WaitForStatus('Running', (New-TimeSpan -Seconds120))
Write-RemediationLog 'INFO''Sense service started.'$changed = $true
}
else {
Write-RemediationLog 'INFO''Sense service already running - no start action needed.'
}
# ---- Verify the final state ----$finalService = Get-Service -Name$senseServiceNameif ($finalService.Status -ne'Running') {
Write-RemediationLog 'ERROR'"Sense service did not reach Running state (current: $($finalService.Status)). Check the Microsoft-Windows-Sense/Operational event log."
exit 1
}
if ($changed) { Write-RemediationLog 'INFO''Sense service remediation applied; service is running.' }
else { Write-RemediationLog 'INFO''Device already compliant - no changes made.' }
exit 0
}
catch {
Write-RemediationLog 'ERROR'"Remediation failed: $($_.Exception.Message)"
exit 3
}
finally {
Write-RemediationLog 'INFO''EDR service remediation finished.'
}
The scope decision matters: an onboarded-but-stopped service is a local repair, while a
device with no onboarding markers needs its MDE configuration policy re-examined in Intune.
Keeping those separate prevents a script from papering over a policy gap.
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.
Deploying Through Intune
Sign in to the Microsoft Intune admin center.
Go to Devices → Scripts and remediations → + Add, platform Windows 10/11.
Name it something explicit, for example Remediate - Defender EDR sensor health, and describe the blast radius ("sets Sense service to Automatic and starts it; never touches onboarding or AV policy").
Upload detect.ps1 on the Detection script tab. Set Run script in 64-bit PowerShell: Yes and Run this script using signed-on credentials: No.
Upload remediate.ps1 on the Remediation script tab with the same context settings.
Schedule the package to run Daily during your rollout and Weekly once healthy. Sensor health degrades quietly, so recurring detection is the point.
Assign to a test device group first, then widen to your production rings. Exclude any devices that intentionally run third-party antivirus in passive mode, or accept that they will report as findings by design.
Notes for this package:
Signed-on credentials: No. All checks are machine-scoped and run fine as SYSTEM.
If your security team signs internal scripts, enable the signature check and sign both
files; otherwise leave the enforcement check off and rely on your assignment hygiene.
Exit Codes
Code
Meaning
0
Healthy: Sense running, onboarding markers present, antivirus in Normal mode (detection) — or the service repair succeeded / already running (remediation)
1
Issue detected: Sense missing, disabled, or stopped; onboarding key absent; or antivirus passive / real-time protection off. Remediation exit 1 means the service could not reach Running
2
Antivirus runtime unreadable (detection) — state unknown; Sense service not installed (remediation) — the MDE platform itself needs deploying
3
Unexpected script error — inspect the log
Logging
Detection writes to C:\ProgramData\Company\Logs\EdrAvDetection.log.
Remediation writes to C:\ProgramData\Company\Logs\EdrAvRemediation.log.
Lines are UTC-timestamped and leveled (INFO, WARN, ERROR). The detection log records
each check's result, so a single file tells you which of the three signals failed. For the
agent's own view, cross-reference Defender sensor logs and the Microsoft Defender portal's
device timeline; both carry more detail than any local script can provide.
Troubleshooting the Script
Exit 2 on detection across a whole ring. Get-MpComputerStatus is failing to return
status. Confirm the Defender platform is installed and updated; a corrupted platform
shows exactly this way.
Sense keeps stopping after the fix. Look for platform damage or conflicting
third-party agents. The service repair starts the sensor; it cannot keep it alive if
something is killing it.
Onboarding key missing but service healthy. The onboarding policy did not reach the
device. Check the MDE configuration policy assignment, scope tags, and filters in
Intune before touching the device.
Passive mode findings everywhere after a security tool pilot. That is by design:
the third-party product flipped Defender to passive. Decide intentionally whether that
is acceptable and exclude those devices, or remove the third-party agent.
No log file at all. The package never ran. Verify assignment, check-in, and whether
a signature-check enforcement conflict blocked execution.
How to Validate the Fix
On a flagged device, run detect.ps1 manually in an elevated 64-bit console; expect
exit 1 with the failing signal named in the log.
Run remediate.ps1; expect exit 0 and a log line showing the enable/start action.
Re-run detection; it must return 0 with all three signals healthy.
In the Microsoft Defender portal, confirm the device reports in and its sensor health
shows active within your normal reporting window.
In Intune, open the remediation package and confirm the device reports "Remediated" or
"Compliant" after its next sync.
Production Considerations
Execution context. Both scripts run as SYSTEM in 64-bit Windows PowerShell; no user
token or profile access is involved.
Idempotency. Detection is read-only. Remediation enables and starts the service and
reports "already compliant" on healthy devices, so repeated runs are safe.
Side effects. Starting the Sense service causes the sensor to resume reporting; no
reboot is involved. The script never restarts a running service, so active sensor
sessions are not interrupted.
Security. No credentials or onboarding blobs appear in the scripts. Registry access
is read-only in detection. Have your PowerShell automation SME and security team review
the scripts and validate them on a test ring before broad production rollout, consistent
with your script signing and change-control policy.
Scope control. Keep assignments in device groups you can drain quickly, and keep the
passive-mode exclusion list explicit so findings stay actionable.
The Sense service is running but the device never appears in the Defender portal. What now?
The service running locally is necessary but not sufficient. Check the onboarding markers
this script detects, then confirm the device has network access to the Defender service
endpoints and that its onboarding configuration was actually applied. Devices onboarded
with the wrong tenant ID report locally healthy but never show up where you expect.
Why does the script report passive mode as an issue if third-party antivirus is supported?
Passive mode is a supported state, but it is a policy decision, not an accident you want
in your fleet. The script's job is to make the state visible so security teams can either
accept it explicitly for specific devices or remove the conflicting product. Silent
passive mode is how estates end up with no primary antivirus at all.
Can the remediation re-onboard a device by writing the onboarding blob?
No, and it should not. Onboarding blobs are tenant-specific configuration data that must
be delivered by the management system you trust. The script repairs the local service and
reports the rest; re-onboarding is done by re-applying the MDE onboarding policy through
Intune, which keeps the device's configuration aligned with your tenant.
Comments
0No comments yet — be the first to share your thoughts.