Domain 3 β€” Module 1 of 6 17%
23 of 28 overall
Domain 3: Perform Threat Hunting Free ⏱ ~14 min read

KQL Foundations for Threat Hunters

KQL is the language of threat hunting. Learn how to identify the right tables, use essential operators, and write queries that find what your detections missed.

Why KQL matters for SC-200

Simple explanation

KQL is like a search engine for your security data. Instead of browsing millions of log entries manually, you write a query that finds exactly what you need: β€œShow me all failed logins from Russia in the last 24 hours” or β€œFind every device that ran PowerShell with a download command.”

Kusto Query Language (KQL) is the query language used in both Defender XDR (Advanced Hunting) and Microsoft Sentinel. Every threat hunter, detection engineer, and senior SOC analyst uses it daily.

This module teaches the foundations β€” the tables, the operators, and the patterns you need to start hunting. The next module takes it further with real-world Advanced Hunting queries.

The most important tables

Knowing which table to query is half the battle. Here are the key tables in Defender XDR Advanced Hunting:

Endpoint tables (Defender for Endpoint)

TableWhat It ContainsWhen to Use
DeviceEventsMiscellaneous device events (ASR triggers, tamper protection, etc.)Catch-all for non-standard events
DeviceProcessEventsProcess creation with command linesHunting for malicious processes, LOLBins
DeviceNetworkEventsNetwork connections from devicesC2 communication, data exfiltration
DeviceFileEventsFile creation, modification, deletionMalware drops, data staging
DeviceRegistryEventsRegistry modificationsPersistence mechanisms
DeviceLogonEventsLogon events on devicesLateral movement, credential use
DeviceImageLoadEventsDLL loading eventsDLL sideloading, injection

Email tables (Defender for Office 365)

TableWhat It Contains
EmailEventsEmail metadata (sender, recipient, subject, delivery action)
EmailAttachmentInfoAttachment details (name, type, hash)
EmailUrlInfoURLs found in emails
EmailPostDeliveryEventsPost-delivery actions (ZAP removals, user reports)

Identity tables

TableWhat It Contains
IdentityLogonEventsSign-in events from Entra ID and on-prem AD
IdentityQueryEventsAD queries (LDAP, DNS) β€” reconnaissance detection
IdentityDirectoryEventsAD directory changes (group membership, password resets)

Cloud app tables

TableWhat It Contains
CloudAppEventsActivities in connected cloud apps (Defender for Cloud Apps)
Exam tip: table selection is heavily tested

The exam often describes a hunting scenario and asks β€œwhich table should you query?” Match the data type:

  • β€œFind processes running on endpoints” β†’ DeviceProcessEvents
  • β€œFind network connections from devices” β†’ DeviceNetworkEvents
  • β€œFind phishing emails” β†’ EmailEvents + EmailUrlInfo
  • β€œFind suspicious sign-ins” β†’ IdentityLogonEvents
  • β€œFind file downloads on devices” β†’ DeviceFileEvents
  • β€œFind LDAP reconnaissance” β†’ IdentityQueryEvents

Essential KQL operators

KQL queries flow from left to right through pipe operators:

Table
| where TimeGenerated > ago(24h)
| where ColumnName == "value"
| project Column1, Column2, Column3
| sort by Column1 desc
| take 10

The operators you must know

OperatorWhat It DoesExample
whereFilter rows matching a conditionwhere FileName == "powershell.exe"
projectSelect specific columnsproject Timestamp, DeviceName, FileName
extendCreate calculated columnsextend DurationMin = Duration / 60
summarizeAggregate data (count, sum, avg)summarize Count = count() by DeviceName
sort by / order byOrder resultssort by Timestamp desc
take / limitReturn first N rowstake 100
joinCombine two tables on a common columnjoin kind=inner (Table2) on CommonColumn
renderVisualise results as chartrender timechart

String operators

OperatorWhat It DoesCase-Sensitive?
==Exact matchYes
=~Exact match (case-insensitive)No
hasContains a whole word tokenNo
containsContains substring anywhereNo
startswithStarts with stringNo
matches regexRegular expression matchYes
has_anyContains any of the listed valuesNo
inMatches any value in a listYes
Exam tip: has vs contains

has is faster than contains because it matches whole word tokens (indexed search). contains does substring matching (full scan).

  • "powershell" has "power" β†’ false (not a whole token)
  • "powershell" contains "power" β†’ true (substring match)
  • "Microsoft PowerShell" has "PowerShell" β†’ true (whole word token)

For the exam: use has when looking for whole terms, contains when looking for substrings. has is the recommended default for performance.

Your first hunting queries

Find suspicious PowerShell activity

DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName == "powershell.exe"
| where ProcessCommandLine has_any ("Invoke-WebRequest", "wget", "curl", "DownloadString", "DownloadFile")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
| sort by Timestamp desc

Find failed sign-ins from unusual locations

IdentityLogonEvents
| where Timestamp > ago(7d)
| where ActionType == "LogonFailed"
| summarize FailedCount = count() by AccountUpn, Location
| where FailedCount > 10
| sort by FailedCount desc

Find emails with suspicious attachments

EmailAttachmentInfo
| where Timestamp > ago(24h)
| where FileType in ("exe", "scr", "js", "vbs", "ps1", "bat", "cmd")
| join kind=inner (EmailEvents) on NetworkMessageId
| project Timestamp, SenderFromAddress, RecipientEmailAddress, Subject, FileName, FileType
Question

What is the difference between 'has' and 'contains' in KQL?

Click or press Enter to reveal answer

Answer

'has' matches whole word tokens (indexed, fast). 'contains' matches substrings anywhere (full scan, slower). Example: 'PowerShell' has 'Power' = false. 'PowerShell' contains 'Power' = true. Use 'has' as default for performance.

Click to flip back

Question

Which table would you query to find lateral movement via RDP?

Click or press Enter to reveal answer

Answer

DeviceLogonEvents β€” filter for LogonType = RemoteInteractive. This table captures all logon events on devices including interactive, network, and remote (RDP) logons.

Click to flip back

Question

What does the 'summarize' operator do in KQL?

Click or press Enter to reveal answer

Answer

Aggregates rows by grouping columns. Common functions: count() (number of rows), sum(), avg(), min(), max(), dcount() (distinct count), make_set() (unique values as array). Example: summarize FailedLogins = count() by UserName groups failed logins per user.

Click to flip back

Knowledge Check

Tyler wants to find all devices that connected to a specific C2 IP address (198.51.100.42) in the last 24 hours. Which table should he query?

Knowledge Check

Anika writes a query: `DeviceProcessEvents | where FileName has 'power'`. What results will this return?

Next up: KQL foundations are set. Now let’s write real-world Advanced Hunting queries in Defender XDR β€” detecting threats across endpoints, email, and identity.