Beta

We are still building. Join us, help test, and tell us what would make this great.

Send feedback
← Articles

Must-Have KQL for Intune, Defender, and Entra Investigations

Rod Trent@rodtrent

A practical collection of short, copy-paste KQL queries for the everyday investigation questions that come up across Intune, Microsoft Defender, and Entra ID. These starters cover non-compliant devices, risky sign-ins, vulnerability status, and sensor health so you can get answers faster and spend more time on the actual work.

Must-Have KQL for Intune, Defender, and Entra Investigations

When something breaks or looks suspicious, the last thing you want is to spend ten minutes rebuilding a basic query from scratch. These are the short, copy-paste starters I keep within reach for the most common investigation questions across Intune, Microsoft Defender, and Entra ID.

They’re deliberately simple. Change the time range, add a device or user filter, and keep moving. Note the environment each one expects:

  • Log Analytics / Microsoft Sentinel uses TimeGenerated and tables such as SigninLogs, AADRiskyUsers, and IntuneDeviceComplianceOrg (Intune requires Diagnostic Settings configured to a workspace).
  • Advanced Hunting (Defender portal) uses Timestamp and tables such as DeviceTvmSoftwareVulnerabilities and DeviceInfo.

Entra ID: Risky sign-ins and risky users

These surface the accounts and sessions that Identity Protection has already flagged.

Recent medium or high risk sign-ins (Log Analytics / Sentinel):

kql
SigninLogs
| where TimeGenerated > ago(7d)
| where RiskLevelDuringSignIn in~ ("medium", "high")
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName,
          RiskLevelDuringSignIn, RiskState, RiskDetail, LocationDetails
| order by TimeGenerated desc

High-risk users still marked at risk (Log Analytics / Sentinel):

kql
AADRiskyUsers
| where RiskLastUpdatedDateTime > ago(7d)
| where RiskLevel == "high" and RiskState == "atRisk"
| project UserPrincipalName, RiskLevel, RiskState, RiskDetail, RiskLastUpdatedDateTime
| order by RiskLastUpdatedDateTime desc

Use the first when you’re looking at a specific time window of activity. Use the second when you want the current list of accounts that still need attention.

Defender: Vulnerability status

Best run in Advanced Hunting. These help answer “which devices are exposed right now?” without opening the full Vulnerability Management blade.

Devices with high/critical vulnerabilities that have public exploits:

kql
DeviceTvmSoftwareVulnerabilities
| where VulnerabilitySeverityLevel in ("High", "Critical")
| where IsExploitAvailable == true
| summarize VulnCount = dcount(CveId) by DeviceName, OSPlatform
| order by VulnCount desc
| take 50

Top software by number of affected devices:

kql
DeviceTvmSoftwareVulnerabilities
| summarize Devices = dcount(DeviceId), CVEs = dcount(CveId) by SoftwareName
| order by Devices desc
| take 20

The first is useful for prioritization during an incident or after a new critical CVE is announced. The second quickly shows which products are creating the most exposure across the environment.

Intune: Non-compliant devices

Requires Intune diagnostic data flowing into a Log Analytics workspace. This gives a clean, current list of devices that are reporting as non-compliant and have checked in recently.

kql
IntuneDeviceComplianceOrg
| where todatetime(LastContact) > ago(30d)
| where ComplianceState == "Not compliant"
| summarize arg_max(TimeGenerated, *) by DeviceName
| project DeviceName, ComplianceState, LastContact, OS, OSDescription
| order by LastContact desc

Pair this with Conditional Access reports when you’re seeing unexpected blocks. Devices that stop reporting will eventually fall out of compliance based on your validity period settings; this query keeps the focus on ones that are still active.

Bonus: Defender sensor health

A quick way to find onboarded devices whose sensor is not currently healthy. Run in Advanced Hunting.

kql
DeviceInfo
| where Timestamp > ago(14d)
| summarize arg_max(Timestamp, *) by DeviceId
| where OnboardingStatus == "Onboarded" and SensorHealthState != "Active"
| project DeviceName, OSPlatform, SensorHealthState, Timestamp
| order by Timestamp desc

Devices in this list are onboarded but not fully protected. Common causes include proxy interference, the sensor service stopped, or incomplete onboarding policy deployment.

How to use these

Start with the query closest to the question you’re being asked. Tighten the time range, add | where DeviceName == "specific-device" or | where UserPrincipalName == "user@domain.com", and project only the columns you actually need for the ticket or chat. Most of these become one-liners once you know the pattern.

These are investigation starters, not finished detection rules. They get you answers quickly so you can spend the rest of the time on context, confirmation, and remediation.

Discussion

Open in forums

Comments here are a forum thread. A reply shows up in both places.

No comments yet.

Sign in to comment.