The Device Was Compliant — The Session Wasn't
The device was managed.
It was enrolled. It was compliant. Conditional Access allowed the sign-in.
On paper, everything looked exactly as it should.
Then the account began accessing resources from a pattern that did not match the trusted endpoint.
The device was compliant. The session still needed investigating.

Session Investigation
A trusted device is evidence. It is not the end of the investigation.
The compliant-device signal looked reassuring
Start with successful sign-ins from compliant devices
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
SigninLogs
| where TimeGenerated > ago(7d)
| where UserPrincipalName =~ "alex.morgan@contoso.com"
| where ResultType == "0"
| extend DeviceId = tostring(DeviceDetail.deviceId),
IsCompliant = tobool(DeviceDetail.isCompliant),
IsManaged = tobool(DeviceDetail.isManaged),
OperatingSystem = tostring(DeviceDetail.operatingSystem),
Browser = tostring(DeviceDetail.browser)
| where IsCompliant == true
| project TimeGenerated, UserPrincipalName, AppDisplayName,
IPAddress, DeviceId, IsCompliant, IsManaged,
OperatingSystem, Browser, ConditionalAccessStatus,
AuthenticationRequirement, CorrelationId
| order by TimeGenerated asc
Compare the same account across device identities and IP addresses
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName =~ "alex.morgan@contoso.com"
| where ResultType == "0"
| extend DeviceId = tostring(DeviceDetail.deviceId),
IsCompliant = tostring(DeviceDetail.isCompliant),
OS = tostring(DeviceDetail.operatingSystem),
Browser = tostring(DeviceDetail.browser)
| summarize SignIns = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IPAddress, DeviceId, IsCompliant, OS, Browser,
AppDisplayName, IsInteractive
| order by FirstSeen asc
Verify the trusted endpoint in Defender XDR
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
DeviceInfo
| where Timestamp > ago(7d)
| where AadDeviceId == "00000000-0000-0000-0000-000000000042"
| summarize arg_max(Timestamp, *) by DeviceId
| project Timestamp,
DeviceName,
DeviceId,
AadDeviceId,
OSPlatform,
OSVersion,
MachineGroup,
LoggedOnUsers
Ask whether the trusted endpoint made the suspicious connection
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
DeviceNetworkEvents
| where Timestamp between (datetime(2026-08-17T01:45:00Z) .. datetime(2026-08-17T03:00:00Z))
| where DeviceName =~ "LAPTOP-042"
| where RemoteIP == "203.0.113.45"
or RemoteUrl =~ "suspicious.example"
| project Timestamp,
DeviceName,
InitiatingProcessAccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine,
RemoteIP,
RemotePort,
RemoteUrl,
Protocol
| order by Timestamp asc
Look for non-interactive token use after the trusted sign-in
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName =~ "alex.morgan@contoso.com"
| where ResultType == "0"
| where IsInteractive == false
| extend DeviceId = tostring(DeviceDetail.deviceId),
IsCompliant = tostring(DeviceDetail.isCompliant)
| project TimeGenerated,
AppDisplayName,
ResourceDisplayName,
IPAddress,
IncomingTokenType,
DeviceId,
IsCompliant,
ConditionalAccessStatus,
CorrelationId
| order by TimeGenerated asc
Build the session timeline instead of trusting a single field
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName =~ "alex.morgan@contoso.com"
| where ResultType == "0"
| extend DeviceId = tostring(DeviceDetail.deviceId),
IsCompliant = tostring(DeviceDetail.isCompliant),
OS = tostring(DeviceDetail.operatingSystem),
Browser = tostring(DeviceDetail.browser)
| project TimeGenerated,
IsInteractive,
AppDisplayName,
IPAddress,
DeviceId,
IsCompliant,
OS,
Browser,
IncomingTokenType,
ConditionalAccessStatus,
CorrelationId
| order by TimeGenerated asc

