Investigating DeviceLogonEvents in Microsoft Defender XDR
DeviceLogonEvents records user logons and authentication activity on endpoints protected by Microsoft Defender XDR.
It helps defenders determine who accessed a device, how they authenticated and whether the activity was legitimate.
In this lesson, you'll learn how to investigate logons, failed sign-ins, remote access and suspicious account activity using DeviceLogonEvents.
Lesson overview
Learn how DeviceLogonEvents helps defenders investigate endpoint authentication, local account usage, RDP-style access and failed logon patterns.
Why DeviceLogonEvents matters
Investigation scenario
Step 1 — Review recent DeviceLogonEvents activity
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
DeviceLogonEvents | where Timestamp > ago(7d) | project Timestamp, DeviceName, ActionType, LogonType, AccountDomain, AccountName, AccountUpn, AccountSid, RemoteIP, RemoteDeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, ReportId | order by Timestamp desc
Step 2 — Find failed logon patterns
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
DeviceLogonEvents | where Timestamp > ago(14d) | where ActionType == "LogonFailed" | summarize FailedLogons = count(), Devices = dcount(DeviceName), RemoteIPs = dcount(RemoteIP), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by AccountDomain, AccountName, LogonType | top 50 by FailedLogons desc
Step 3 — Hunt for remote interactive logons
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
DeviceLogonEvents | where Timestamp > ago(30d) | where ActionType == "LogonSuccess" | where LogonType has_any ("RemoteInteractive", "Network") | project Timestamp, DeviceName, AccountDomain, AccountName, AccountUpn, LogonType, RemoteIP, RemoteDeviceName | order by Timestamp desc
Step 4 — Build a timeline for one account
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
let TargetAccount = "replace-with-account-name"; DeviceLogonEvents | where Timestamp between (ago(24h) .. now()) | where AccountName =~ TargetAccount or AccountUpn =~ TargetAccount | project Timestamp, DeviceName, ActionType, LogonType, RemoteIP, RemoteDeviceName, InitiatingProcessFileName, LogonId | order by Timestamp asc
Step 5 — Join DeviceLogonEvents with DeviceInfo
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
let RecentDeviceInfo = DeviceInfo | where Timestamp > ago(30d) | summarize arg_max(Timestamp, *) by DeviceId | project DeviceId, OSPlatform, ExposureLevel, RiskScore; DeviceLogonEvents | where Timestamp > ago(7d) | join kind=leftouter RecentDeviceInfo on DeviceId | project Timestamp, DeviceName, OSPlatform, ExposureLevel, RiskScore, ActionType, LogonType, AccountName, RemoteIP | order by Timestamp desc
Step 6 — Compare endpoint logons with identity logons
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let EndpointFailures = DeviceLogonEvents | where Timestamp > ago(7d) | where ActionType == "LogonFailed" | project Timestamp, DeviceName, AccountSid, AccountName, LogonType; EndpointFailures | join kind=leftouter ( IdentityLogonEvents | where Timestamp > ago(7d) | project AccountSid, Protocol, FailureReason, IPAddress ) on AccountSid | project Timestamp, DeviceName, AccountName, LogonType, Protocol, FailureReason, IPAddress
