guideonce.
← All guides

Endpoint Security · macOS · Linux · Windows

Troubleshooting Microsoft Defender for Endpoint from the Command Line

A practical reference for the mdatp CLI on macOS and Linux, plus PowerShell equivalents on Windows. Templates first, examples second, and the diagnostic one-liner I reach for before anything else.

Microsoft Defender for Endpoint (MDE, also still widely called MDATP) is the endpoint security tool I end up debugging most often, because it touches everything: real-time scanning, network protection, EDR telemetry, definition updates, conditional access signals, and tamper protection all live behind one daemon. When something looks wrong in the security portal but the machine itself swears it is fine, or vice versa, the answer is almost always on the device itself, and the way to get it is the CLI. This post is the reference I wish I had bookmarked the first three times I had to debug Defender from scratch.

The same mdatp binary exists on macOS and Linux with the same syntax. Windows uses PowerShell cmdlets like Get-MpComputerStatus and Get-MpPreference, so I cover those at the end for parity. Each command appears first as a template with the variable bits highlighted in orange, then with specific examples. Same pattern as the macOS MDM command reference if you want a similar tour for the rest of the Apple stack.

The Diagnostic One-Liner

This is the first thing I run when a Mac or Linux endpoint shows up acting strangely in the security portal, or when a user reports that Defender keeps complaining about something. It returns the answers to about eighty percent of "is Defender broken?" questions in one short scroll, before any deeper investigation is needed.

What this is actually telling you, in order: is the agent healthy (single boolean), is it licensed (proves the org has paid for this device's protection), is real-time protection switched on, are signatures fresh, what tenant the device is enrolled to, what protection ring (production / preview / insider) it is on, and the agent and definitions versions. Then it tests the network paths back to Microsoft's cloud, and re-prints the EDR org ID and network protection state because those are the two fields people most often ask me about specifically.

If everything in this output looks sensible, the device is fine and the issue is somewhere else: the portal, conditional access, a recent policy push, or genuinely just lag. If anything looks wrong, the rest of this post is for narrowing down which bit is wrong and why.

Reading the Health State

The mdatp health command without arguments dumps every known health field, of which there are dozens. For day-to-day use you almost always want either a filtered view (grep for the fields that matter) or a single field with the --field flag.

Template
mdatp health
mdatp health | grep -E "<field1>|<field2>|<field3>"
mdatp health --field <field-name>
The fields I check most often, and why
FieldWhat it meansWhat to do if it is wrong
healthyOverall yes/no. If false, something else here is broken.Read the rest of the output to find the specific problem.
licensedThe tenant has a licence covering this device.Check Microsoft 365 licensing assignment for the device or user.
org_idThe Defender tenant the device is enrolled to.Empty means not enrolled or onboarding failed. Re-run the onboarding script.
real_time_protection_enabledWhether RTP is currently scanning files on access.If false, see the RTP section below.
definitions_statusWhether signatures are current.up_to_date good, stale bad, not_loaded very bad.
definitions_versionThe actual version string.Compare against Microsoft's current build if you suspect a stuck update.
app_versionDefender agent version on the device.If far behind the current release, the device is missing the auto-update path.
network_protection_statusWhether NP is active.See the network protection section.
release_ringProduction, preview, or insider channel.Test rings will get updates earlier and look different to production.
edr_early_previewWhether early EDR preview features are on.Usually false in production fleets.
tamper_protectionCurrent tamper protection mode.See the tamper protection section.
JSON output for scripting
# Same data, JSON-shaped, parseable by jq or anything else
mdatp health --output json
mdatp health --output json | jq '.real_time_protection_enabled, .definitions_status'

Connectivity and Cloud Reachability

If a device shows up as healthy on the device but inactive in the portal, the cause is usually network. mdatp connectivity test probes each of the URLs Defender needs to reach and reports per-endpoint success or failure.

Templates
# Standard connectivity test, walks every required URL
mdatp connectivity test

# Same, JSON-shaped
mdatp connectivity test --output json

What you are reading in the output is a list of endpoint URLs (telemetry, EDR command-and-control, signature distribution, cloud-delivered protection lookup) and a pass or fail for each. Common failure patterns:

Real-Time Protection and Scan State

If real_time_protection_enabled is false on a device that should have it on, there are a few possible causes worth checking before assuming the agent is broken.

Templates
# Read the current RTP state and managed source
mdatp health --field real_time_protection_enabled
mdatp config real-time-protection

# Turn RTP on locally (only if not enforced by MDM)
mdatp config real-time-protection --value enabled

# Run an on-demand scan against a specific path
mdatp scan custom --path <path-to-scan>

# Quick scan / full scan
mdatp scan quick
mdatp scan full
Examples
mdatp scan custom --path /Users/Shared
mdatp scan custom --path /var/log
mdatp scan custom --path /opt/<app-folder>
Passive mode looks like RTP is off

If the device is intentionally running in passive mode (so another AV vendor handles real-time scanning while Defender provides EDR), the real_time_protection_enabled field will report false and that is correct, not a fault. Check mdatp health --field passive_mode_enabled first before treating disabled RTP as a problem.

Definition Freshness and Updates

Stale signatures are one of the most common reasons a Defender device shows up as unhealthy. The agent updates definitions on a schedule, but proxies, throttled networks, and laptops that have been asleep for days will all cause definitions to fall behind.

Templates
# Check current definition state
mdatp health --field definitions_status
mdatp health --field definitions_version

# Force an immediate definition update
mdatp definitions update

After running an update, re-check definitions_status. If it stays at stale after a forced update, the issue is network connectivity to the signature distribution endpoints. Run mdatp connectivity test and look for the signature URL specifically.

EDR Enrolment and Org ID

The org_id field tells you which Defender tenant a device is enrolled to. An empty org_id usually means onboarding either never completed or was reverted by an offboarding script. This is the single most common reason a device that "should be in Defender" shows up nowhere in the portal.

Templates
# Confirm enrolment to the expected tenant
mdatp health --field org_id
mdatp health --field edr_machine_id
mdatp health --field edr_configuration_version

If org_id is empty, run the onboarding script again. The onboarding script is a per-tenant download from the Defender portal: Settings → Endpoints → Onboarding → macOS/Linux, then download the Python or shell installer. Once executed, give it a minute and re-check org_id. If it is still empty after that, the script either failed silently (check its own log output) or there is a proxy in the way of the EDR enrolment endpoint.

Network Protection State

Network protection (the SmartScreen-style URL and IP-based filtering) is configured separately from antivirus. On macOS especially, it depends on a Network Extension being loaded and approved, which adds a few possible failure modes that AV alone does not have.

Templates
# Read the current state
mdatp health --field network_protection_status
mdatp health --field network_protection_enforcement_level

# Toggle locally (if not MDM-enforced)
mdatp config network-protection enforcement-level --value <audit|block|disabled>

# Temporarily disable the network filter (macOS) for troubleshooting
mdatp system-extension network-filter disable
mdatp system-extension network-filter enable

The enforcement levels mean exactly what they sound like: disabled the feature is off, audit bad traffic is logged but allowed through, block bad traffic is dropped. If you suspect Defender's network filter is interfering with something the user is trying to do (a VPN, a niche app, a corporate web tool that uses a domain Defender flags), audit mode is the right diagnostic intermediate step before disabling entirely.

Exclusion Management

Exclusions are how you tell Defender to stop scanning something. They lower protection, so the rule of thumb is to use the narrowest exclusion that fixes the problem and document why. The CLI lets you list, add, and remove exclusions; if the exclusion was deployed via MDM, the CLI can read it but cannot remove it.

Templates
# List current exclusions
mdatp exclusion list

# Add a path exclusion
mdatp exclusion folder add --path <folder-path>
mdatp exclusion file   add --path <file-path>

# Add a process exclusion (all files opened by this process are skipped)
mdatp exclusion process add --path <process-path>
mdatp exclusion process add --name <process-name>

# Add a file extension exclusion
mdatp exclusion extension add --name <extension-without-dot>

# Remove (same shape, swap "add" for "remove")
mdatp exclusion folder remove --path <folder-path>
mdatp exclusion process remove --name <process-name>
Examples
# Exclude a developer build directory from scanning
mdatp exclusion folder add --path /Users/<username>/build

# Exclude a specific noisy process
mdatp exclusion process add --name node

# Exclude database extensions on a server
mdatp exclusion extension add --name mdb
MDM-deployed exclusions are read-only here

If your fleet uses a managed configuration (/etc/opt/microsoft/mdatp/managed/mdatp_managed.json on Linux, the corresponding profile-deployed plist on macOS), exclusions in that file appear in mdatp exclusion list but the CLI cannot remove them. The CLI only manages locally-defined exclusions. To remove a managed exclusion, you remove it from the managed JSON or profile and let the next sync push the change down.

Tamper Protection State

Tamper protection stops anything other than Defender itself (and a specific list of permitted MDM processes) from disabling or modifying the agent. When it is on, even a local administrator cannot stop Defender from the command line, which is the point.

Templates
# Read the current tamper protection mode
mdatp health --field tamper_protection

# Read the full tamper protection config including managed source
mdatp health --details tamper_protection

# Set mode locally (only if not MDM-enforced; modes: disabled, audit, block)
sudo mdatp config tamper-protection enforcement-level --value <mode>

The reported mode is one of disabled, audit, or block. The --details form is the one worth knowing about: it shows you not just the current mode but where it came from (local, portal, MDM profile) and which mode would apply if you removed each configuration source. This is invaluable when you have multiple configuration sources fighting over the same setting.

Threats and Quarantine

The threat commands let you see what Defender has caught, look at quarantine, and restore quarantined files if something was a false positive.

Templates
# List threats detected on this device
mdatp threat list

# List quarantined items
mdatp threat quarantine list

# Restore a quarantined item by ID (newer agent versions)
mdatp threat quarantine restore --id <threat-id> --path <destination-folder>

# Mark a specific threat as allowed (use sparingly)
mdatp threat allowed add --name "<threat-name>"

The threat IDs come from mdatp threat list. The classic test of any AV is the EICAR string, which Defender catches like every other engine; mdatp threat allowed add --name "EICAR-Test-File (not a virus)" is the documented way to suppress detections of it during validation, not something to use in production.

Diagnostic Log Collection

When you have done everything above and you still cannot work out what is wrong, the next step is to bundle up the Defender logs and either look at them yourself or send them to Microsoft Support.

Templates
# Collect all Defender logs into a zip
sudo mdatp diagnostic create

# Collect to a specific directory rather than the default
sudo mdatp diagnostic create --path <destination-folder>

# Bump the log level temporarily for fuller traces, then restore
sudo mdatp log level set --level verbose
# reproduce the issue
sudo mdatp log level set --level info

# Make the log level persist across restarts
sudo mdatp log level persist --level <level>

The zip is saved to /Library/Application Support/Microsoft/Defender/wdavdiag/ on macOS by default, or /var/opt/microsoft/mdatp/wdavdiag/ on Linux. The output of the command prints the exact path so you do not have to remember.

Performance Troubleshooting

The classic Defender performance complaint is "my Mac is slow when I do X". The diagnostic for this is real-time protection statistics, which tells you which processes are causing the most scan activity.

Templates
# Enable RTP statistics collection (requires real-time protection on)
mdatp config real-time-protection-statistics --value enabled

# Reproduce the slowness, then dump the stats to JSON
mdatp diagnostic real-time-protection-statistics --output json > <output-file>.json

# Parse with the Microsoft-published helper script
curl -O https://raw.githubusercontent.com/microsoft/mdatp-xplat/master/linux/diagnostic/high_cpu_parser.py
python3 high_cpu_parser.py < <output-file>.json | head -n 10

# Disable statistics collection when done
mdatp config real-time-protection-statistics --value disabled

The parser output is a list of processes sorted by how many files Defender scanned because of them. The classic top entries on developer machines are xcodebuild, actool, language compilers, node, and package managers. The fix for any of those is either a narrowly-scoped folder exclusion (the build directory the tool reads from) or a process exclusion for the tool itself, depending on which is safer in your environment.

Common Scenarios I Have Actually Hit

Device shows as inactive in the portal but agent looks fine locally

First check mdatp connectivity test. Nine times out of ten this is a proxy or firewall change blocking telemetry endpoints. The agent will keep working locally for as long as definitions are valid, but the portal will mark it inactive after the heartbeat fails for a few hours.

RTP is off and you cannot turn it back on locally

Check mdatp config real-time-protection to see who is enforcing the setting. If it shows a managed source (MDM profile, portal-pushed policy), you cannot override it locally on purpose, which is the right behaviour. The fix is at the policy source, not on the device.

Definitions stay stale after a forced update

Almost always a connectivity issue to *.msdsec.microsoft.com or the relevant signature distribution URLs. mdatp connectivity test will name the specific endpoint. If you are on a restrictive network, get the URL added to the proxy allow-list or set up local definition mirroring.

Onboarded device showing empty org_id

Either onboarding failed silently or something offboarded it. Check the onboarding script's own log output. The script logs to /Library/Logs/Microsoft/mdatp/install.log on macOS and /var/log/microsoft/mdatp/install.log on Linux. Errors in those files name the cause directly: most often it is a missing approval for the system extension on macOS, or a missing dependency on Linux.

Defender keeps restarting (Linux) or its system extension keeps being killed (macOS)

This is the symptom that means another security tool is fighting Defender. Check the system logs for OOM kills, look for second AV products, and look for any process-killing scripts. The fix is to remove the conflicting tool or, if both must coexist, configure Defender to passive mode for AV while still using it for EDR.

Network protection breaks a specific app or workflow

Set network protection to audit mode (mdatp config network-protection enforcement-level --value audit) and reproduce the issue. Network protection will now log what it would have blocked rather than blocking it, and you can identify the specific URL or IP at fault from the diagnostic logs. From there, either add an exception in policy or accept that the app is doing something risky enough that Defender's block is correct.

Windows PowerShell Equivalents

Windows uses a different toolset. The mdatp binary does not exist there; everything is PowerShell cmdlets in the Defender module, which ship with Windows. These are the commands that map most directly onto what the mdatp equivalents do above.

Health and configuration

Template
# Full Defender state (the rough equivalent of mdatp health)
Get-MpComputerStatus

# Just specific fields
Get-MpComputerStatus | Select-Object <field1>, <field2>
Examples
Get-MpComputerStatus | Select-Object `
    AntivirusEnabled, RealTimeProtectionEnabled, AntispywareEnabled, `
    AMServiceEnabled, AntivirusSignatureLastUpdated, NISEnabled

# Just the bits I check most
Get-MpComputerStatus | Select-Object `
    AntivirusEnabled, RealTimeProtectionEnabled, `
    AntivirusSignatureVersion, AntivirusSignatureAge, `
    BehaviorMonitorEnabled, IsTamperProtected

Preferences and configuration

# Read all current Defender preferences
Get-MpPreference

# Read specific exclusion fields
Get-MpPreference | Select-Object `
    ExclusionPath, ExclusionExtension, ExclusionProcess

Definition updates

# Force a definition update
Update-MpSignature

# Or via the legacy MpCmdRun binary
& "C:\Program Files\Windows Defender\MpCmdRun.exe" -SignatureUpdate

Scans

Templates
Start-MpScan -ScanType QuickScan
Start-MpScan -ScanType FullScan
Start-MpScan -ScanType CustomScan -ScanPath "<path-to-scan>"

Exclusions

Templates
# Add
Add-MpPreference -ExclusionPath      "<path>"
Add-MpPreference -ExclusionExtension "<ext-without-dot>"
Add-MpPreference -ExclusionProcess   "<process-name>"

# Remove
Remove-MpPreference -ExclusionPath      "<path>"
Remove-MpPreference -ExclusionExtension "<ext-without-dot>"
Remove-MpPreference -ExclusionProcess   "<process-name>"

# List
(Get-MpPreference).ExclusionPath
(Get-MpPreference).ExclusionExtension
(Get-MpPreference).ExclusionProcess

Threats

# Threats seen on this device
Get-MpThreat
Get-MpThreatDetection

# Remove all threats found (use carefully)
Remove-MpThreat

Diagnostic log collection

# Collect Defender support logs
& "C:\Program Files\Windows Defender\MpCmdRun.exe" -GetFiles

# Output lands at:
#   C:\ProgramData\Microsoft\Windows Defender\Support\

Connectivity diagnostics

Windows does not have a direct equivalent of mdatp connectivity test. The closest is downloading the MDE Client Analyzer from the Defender portal, running it, and reviewing the network connectivity section. For quick probing you can also test the underlying URL endpoints with Test-NetConnection or Invoke-WebRequest -UseBasicParsing.


Quick-Action Checklist

For when something is wrong and you need to triage fast. Each step links back to the section above with the detail.

  1. Run the diagnostic one-liner first. Eighty percent of the time it tells you the answer or where to look next.
  2. If the agent is unhealthy, read each field from mdatp health in turn. licensed, org_id, real_time_protection_enabled, definitions_status are the four that matter most.
  3. If org_id is empty, re-run the onboarding script and check its log at /Library/Logs/Microsoft/mdatp/install.log (macOS) or /var/log/microsoft/mdatp/install.log (Linux).
  4. If definitions_status is stale, force a definition update with mdatp definitions update, then re-check. If still stale, it is a network/proxy issue.
  5. If RTP is off and you expected it on, confirm it is not intentionally in passive mode, then check the managed source with mdatp config real-time-protection.
  6. If the device is inactive in the portal but the agent is healthy locally, run mdatp connectivity test. Almost always a blocked telemetry endpoint.
  7. For performance complaints, run the RTP statistics flow and check the high CPU parser output. Add a narrowly-scoped exclusion for the worst offender.
  8. If you suspect network protection is breaking something, set it to audit mode and reproduce. The logs will name the URL or IP at fault.
  9. If two products are fighting, look for kernel ext / system ext conflicts in console logs. Either remove one or run Defender in passive mode.
  10. If you cannot work it out from the CLI, run sudo mdatp diagnostic create to bundle the logs and either look yourself or attach the zip to a Microsoft Support case.

Closing Thoughts

Most Defender problems are not Defender problems. They are network problems, policy conflicts, or misaligned expectations about what the agent should be doing. The CLI is so useful precisely because it makes the device's own opinion of itself visible, which is the bit you cannot see from the portal. Bookmark the diagnostic one-liner and you will reach for it more than you expect.

← All guides