Windows Trigger Full Scan For Devices That Have Not Completed One Windows Clients Only
Query
// Initial full scan helper for MDE onboarded devices
// Use this in a custom detection rule with the "Run antivirus scan" (Full scan) action.
let AvModeDescription = dynamic({"0":"Normal", "1":"Passive", "4":"EDR Block"});
let TimeRange = ago(1d);
// Build a set of Windows 10/11 client devices (no servers)
let WinClientDevices =
DeviceInfo
| where Timestamp > TimeRange
| where OSPlatform in ("Windows10", "Windows11")
| summarize arg_max(Timestamp, DeviceName) by DeviceId
| project DeviceId;
// 1. Find devices in Normal AV mode that have NOT completed a full scan
let ScanCandidates =
DeviceTvmInfoGathering
| where Timestamp > TimeRange
| join kind=inner (WinClientDevices) on DeviceId
| extend AdditionalFields = parse_json(AdditionalFields)
| extend AvMode = tostring(AvModeDescription[tostring(AdditionalFields.["AvMode"])])
| extend FullScanStatus = coalesce(
extractjson("$.Full.ScanStatus", tostring(AdditionalFields.AvScanResults)),
"Not available"
)
| where isnotempty(AvMode) and AvMode has "Normal"
| where FullScanStatus !has "Completed"
// one latest TVM record per device
| summarize arg_max(Timestamp, FullScanStatus, DeviceName) by DeviceId
| project DeviceId, DeviceName, FullScanStatus;
// 2. Anchor on DeviceEvents to get a valid event (ReportId + Timestamp)
DeviceEvents
| where Timestamp > TimeRange
| join kind=inner (WinClientDevices) on DeviceId
| summarize arg_max(Timestamp, ReportId) by DeviceId
// 3. Join event anchor to the TVM scan status
| join kind=inner ScanCandidates on DeviceId
// 4. Final output for custom detection + device action
| project
DeviceName,
DeviceId,
FullScanStatus,
ReportId, // REQUIRED for custom detections
Timestamp // REQUIRED for custom detections
| take 50Explanation
This KQL query is designed to identify Windows 10 and Windows 11 client devices that are onboarded to Microsoft Defender for Endpoint (MDE) and have not completed a full antivirus scan. Here's a simplified breakdown of what the query does:
-
Define Variables:
AvModeDescription: Maps antivirus modes to their descriptions (e.g., "Normal", "Passive", "EDR Block").TimeRange: Sets the time range to the last 24 hours.
-
Identify Windows Client Devices:
- Filters out devices running Windows 10 or Windows 11 from the
DeviceInfotable within the last 24 hours. - Keeps the most recent record for each device.
- Filters out devices running Windows 10 or Windows 11 from the
-
Find Devices Needing a Full Scan:
- From the
DeviceTvmInfoGatheringtable, it identifies devices in "Normal" antivirus mode that haven't completed a full scan. - Joins this information with the list of Windows client devices.
- Extracts and checks the full scan status from the device's additional fields.
- From the
-
Anchor on Device Events:
- Uses the
DeviceEventstable to find a valid event for each device, ensuring there's a recent event to anchor the detection. - Joins this event information with the list of devices needing a full scan.
- Uses the
-
Output Results:
- Produces a list of up to 50 devices, including their names, IDs, full scan status, and event details (ReportId and Timestamp), which are required for custom detection rules.
This query is intended to be used in a custom detection rule that triggers a full antivirus scan on devices that haven't completed one recently.
Details

Nathan Hutchinson
Released: February 12, 2026
Tables
DeviceInfoDeviceTvmInfoGatheringDeviceEvents
Keywords
Devices
Operators
letdynamicagoinsummarizearg_maxprojectwherejoinkind=innerextendparse_jsontostringcoalesceextractjsonisnotemptyhas!hastake