Hunt for Threats by Using Microsoft Defender XDR
KQL fundamentals: reading a query as a pipeline
A hunt for a suspicious PowerShell launch looks like this in advanced hunting[1]:
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("-enc", "-EncodedCommand", "FromBase64String")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName
| order by Timestamp desc
Read it top to bottom and every line is one transformation of the table above it. Kusto Query Language (KQL) is a read-only query language, so this query searches telemetry and returns rows; it never changes a device. The query starts at a table (DeviceProcessEvents) and flows through operators joined by the pipe character |, each taking the previous step's rows as input and passing its output down, exactly like a Unix pipe. That is the whole mental model: a table goes in the top, each line filters or reshapes it, a result table comes out the bottom.
Filter first, project last
The one performance rule the exam leans on: put your time filter and your most selective where conditions as early as possible, so every operator after them works on fewer rows. Microsoft's query best practices[2] say to apply time filters first and to filter before you summarize or join. Projecting columns (project) belongs near the end, once you know which rows survive.
The operators you must recognize
| Operator | What it does | Note for the exam |
|---|---|---|
where | Keeps rows matching a predicate | Filter early; chain several where lines |
project / project-away | Selects / drops columns | Narrows the output; do it last |
extend | Adds a computed column | Does not drop existing columns |
summarize | Aggregates with count(), dcount(), make_set(), grouped by | Collapses rows into groups |
join | Combines two tables on a key | Default is innerunique, not inner |
union | Stacks rows from multiple tables | Use when several tables share an entity |
order by / sort by | Sorts rows | Pair with take to cap output |
take / limit | Returns N arbitrary rows | For sampling, not for "top N"; use top for ranked |
String matching that trips candidates
KQL string operators are the classic exam distractor. == is case-sensitive equality; =~ is case-insensitive equality, which is why the example uses =~ "powershell.exe". has matches a whole indexed term and is fast; contains matches any substring and is slower because it cannot use the term index. The datatypes and operators reference[3] lists the full set. Prefer has/has_any over contains for performance, and remember that =~ (case-insensitive) is the safe default when matching file names that an attacker can re-case.
The advanced hunting schema: which table owns the entity
The first real decision in any hunt is which table to start from, because Defender XDR splits its telemetry into tables grouped by the product that emits them. There is no single "events" table; you query the table that owns the entity you care about. The schema reference[4] documents every table and column, and the portal's schema pane plus a quick TableName | take 10 let you inspect columns before committing.
The table families
- Device* (Microsoft Defender for Endpoint):
DeviceProcessEvents,DeviceNetworkEvents,DeviceFileEvents,DeviceRegistryEvents,DeviceLogonEvents,DeviceImageLoadEvents, plusDeviceInfoandDeviceNetworkInfofor current device state. These are your process, network, file, and sign-in telemetry from onboarded endpoints. - Email* and Url (Microsoft Defender for Office 365):
EmailEvents(every message),EmailAttachmentInfo,EmailUrlInfo,EmailPostDeliveryEvents, andUrlClickEvents(Safe Links verdicts when a user clicks). This is how you trace a phishing campaign from delivery to click. - Identity* (Microsoft Defender for Identity):
IdentityLogonEvents,IdentityDirectoryEvents,IdentityQueryEventsfor on-premises Active Directory and hybrid identity activity. - Cloud and sign-in:
CloudAppEvents(Defender for Cloud Apps),AADSignInEventsBetaandAADSpnSignInEventsBetafor Microsoft Entra ID sign-ins, andAlertEvidence/AlertInfowhich expose the alerts themselves so you can hunt over what already fired.
Joining across products is the point
Cross-product hunting is what advanced hunting is for: follow an attacker from a phished mailbox (EmailEvents) to the click (UrlClickEvents) to a process on the device (DeviceProcessEvents) to a sign-in (IdentityLogonEvents). You combine tables with join (on a shared key like AccountUpn or DeviceId) or union (when several tables share the same entity column). One subtlety the exam tests: KQL join defaults to the innerunique flavor, which de-duplicates the left side, so when you need every matching pair you state join kind=inner explicitly. The join operator docs[5] list all the kinds.
Lookback and limits
Advanced hunting queries the last 30 days[1] of data and a single query is bounded by a result and time budget, so an estate-wide hunt over months is a Microsoft Sentinel job (long-term retention and search jobs), not an advanced hunting one. Keep the lookback as tight as the hunt allows; ago(7d) returns faster than ago(30d) and is usually enough to confirm or rule out an indicator.
Creating custom hunting queries and promoting them
Writing a good hunting query is an iterative loop, then a promotion. You start broad, confirm the results are real and not noisy, then narrow until the query reliably finds the threat with few false positives. The exam frames this as the difference between a one-off interactive hunt and a standing detection.
Save, share, schedule
A query you will reuse is saved as a shared or private query[6] so the team can run it again. To make it run by itself, you promote it to a custom detection rule with Create detection rule directly from the query editor, which is documented in custom detections[7]. That is the hand-off point: this subtopic owns authoring the KQL, and the rule's frequency, alert tuning, and response actions are the detections subtopic.
Required columns for promotion
For the promotion to produce a usable alert, the query must project the columns Defender XDR needs to build one. The rule-creation guidance[7] requires a timestamp column, an entity to map the alert to a real asset, plus a ReportId for non-endpoint tables or a DeviceId for Defender for Endpoint tables so the alert ties back to the originating event. A query that aggregates everything away with summarize and drops these columns cannot become a detection.
// A hunt shaped so it can become a detection:
DeviceLogonEvents
| where Timestamp > ago(1h)
| where ActionType == "LogonFailed"
| summarize FailedAttempts = count(), ReportId = take_any(ReportId)
by DeviceId, AccountName, bin(Timestamp, 1h)
| where FailedAttempts > 50
Use the built-ins instead of starting blank
Don't hand-write everything. The query editor ships functions (built-in helpers like FileProfile() that enrich a file hash with prevalence and reputation), a library of community and Microsoft sample queries on GitHub[1], and the guided hunting mode where you build a query with dropdowns instead of writing KQL, which lets analysts who don't know the language still hunt. Reach for a sample query or a function before composing a complex join from scratch.
Interpreting threat analytics in the Defender portal
Threat analytics answers a different question from advanced hunting. A hunt asks "who touched this indicator"; threat analytics[8] asks "is this active campaign affecting us right now". It is a feed of expert reports written by Microsoft security researchers, each describing a threat actor, campaign, or technique, and then overlaid onto your own tenant's data so the answer is specific to you, not generic malware encyclopedia content. The analyst task on SC-200 is interpretation and response, not authoring intel.
What a report shows you
Each threat analytics report has tabs that turn intel into action against your estate, per the docs[8]:
- Overview / Analyst report: the narrative, the actor, and the techniques, with MITRE ATT&CK[8] technique references.
- Impacted assets: the exact devices, users, and mailboxes in your tenant with related activity, so you can scope the blast radius.
- Related incidents / alerts: the alerts already raised in your queue that map to this threat, linking the campaign to live work.
- Endpoints exposure and Recommended actions: two tabs that together show your exposure level and the recommended mitigations and secure-configuration settings still missing, ranked so you can close the gaps the campaign exploits. Mitigation status is measured against your applied configuration, so it updates as you remediate.
The dashboard's three lenses
The threat analytics dashboard summarizes the feed three ways to drive triage: Latest threats (most recently published or updated reports), High-impact threats (those with the greatest effect on your organization, by impacted-asset count), and Highest-exposure threats (those where your configuration leaves you most exposed). Use high-impact and high-exposure, not a generic severity label, to decide which campaign to hunt or harden first. The reports also surface hunting queries you can run directly, which is the bridge back to advanced hunting: read the report, then pivot into a KQL hunt for the same indicators.
Exam-pattern recognition
SC-200 items on this subtopic cluster into a few recognizable stems. Learn the tell and the right answer.
"Filter as early as possible" / fastest query
When a stem shows a query and asks how to make it faster or which line order is correct, the answer is filter first: the time filter (where Timestamp > ago(...)) and selective where conditions go immediately after the table, before summarize, join, or project. A query that filters after aggregating, or projects before filtering, is the wrong choice. Prefer has over contains, per the best practices[2].
Case sensitivity and string operators
If the stem matches a file name or account that an attacker could re-case, the correct operator is the case-insensitive one: =~ for equality, and the has family is term-based. The distractor is == (case-sensitive), which silently misses PowerShell.exe when the query looked for powershell.exe. See the string operators reference[3].
"Run on a schedule and alert" vs "find it once"
A stem describing a recurring need ("alert whenever", "every time this happens", "continuously detect") points to promote the query to a custom detection rule, not to running the hunt repeatedly by hand. A stem describing a single investigation ("find which devices ran", "did anyone receive") points to a plain advanced hunting query. The trap is choosing a custom detection for a one-time lookup, or re-running a manual hunt for something that should be a standing rule.
Required-columns trap
When a stem says a query "cannot be turned into a custom detection" or "the alert has no asset", the cause is missing required columns: no timestamp, no entity, or no ReportId (non-endpoint tables) / DeviceId (Defender for Endpoint tables). The fix is to project those columns, not to change the frequency. This is documented in custom detection rules[7].
Threat analytics vs advanced hunting
When the question is "are we affected by campaign X" or "which mitigations reduce our exposure to this actor", the answer is threat analytics, because it overlays Microsoft intel onto your tenant. When the question is "search our data for this hash/IP/command line", the answer is advanced hunting. The trap is reaching for advanced hunting to assess a named campaign's impact, or expecting threat analytics to run an arbitrary KQL search.
Retention boundary: Defender XDR vs Sentinel
A stem mentioning data older than ~30 days, long-term retention, archived logs, search jobs, or MITRE ATT&CK coverage analysis is pointing at Microsoft Sentinel, not Defender XDR advanced hunting. Advanced hunting's window is about 30 days; anything beyond it, or the Sentinel-specific hunting features, belongs to the Sentinel hunting subtopic.
Three hunting jobs in Microsoft Defender XDR
| Job | Advanced hunting (KQL) | Threat analytics | Promote to custom detection |
|---|---|---|---|
| What you do | Write a KQL query over raw event tables | Read a curated report mapped to your tenant | Save a validated query as a scheduled rule |
| Question it answers | Who/what touched this indicator? | Are we affected by this campaign now? | How do I detect this automatically from now on? |
| Data it uses | ~30 days of Device/Email/Identity/CloudApp tables | Microsoft intel overlaid on your telemetry | The same query, re-run on a frequency |
| Output | An interactive result table to pivot from | Impacted assets, related alerts, exposure gaps | Alerts plus optional auto-response actions |
| Read vs act | Read-only; you pivot and decide | Read intel, then act on exposure | Acts: alerts and can isolate/disable/delete |
Decision tree
Sharp facts the exam loves — give these one last read before exam day.
Cheat sheet
Sharp facts the exam loves — scan these before test day.
- Advanced hunting is a read-only KQL search over ~30 days of raw Defender XDR telemetry
Advanced hunting in the Microsoft Defender portal lets you query the raw event tables Defender XDR collects from endpoints, identities, email, apps, and cloud, going back about 30 days, using Kusto Query Language (KQL). It is proactive: you run a query and pivot from the result table rather than waiting for an alert. The query is read-only against telemetry, so a hunt never changes a device or mailbox; any containment is a separate response action. When you need data older than ~30 days, that is a Microsoft Sentinel job, not advanced hunting.
- Read a KQL query as a pipeline: a table in at the top, each pipe transforms the rows below
Every advanced hunting query starts at a table name and flows left to right through operators joined by the pipe character, each one taking the previous step's rows as input, just like a Unix pipe. Read it top to bottom and each line is one transformation of the table above it. The core operators are where (filter), project and extend (choose or compute columns), summarize (aggregate), join and union (combine tables), and order/take (sort and limit). Internalizing the pipeline shape is what lets you compose and debug a hunt rather than memorize snippets.
- Filter first: put the time window and selective where conditions right after the table
The performance rule SC-200 leans on is filter early. Place your time filter (where Timestamp > ago(...)) and your most selective where conditions immediately after the table, before summarize, join, or project, so every later operator works on fewer rows. Microsoft's query best practices say to filter before aggregating or joining and to project the columns you want last. A query that aggregates or projects before filtering is the slow, wrong answer on the exam.
Trap Filtering after a summarize or join; the aggregation already processed the full row set, so the late where saves nothing and the query stays slow.
- Match file names with =~ (case-insensitive), not == (case-sensitive)
In KQL == is case-sensitive equality and =~ is case-insensitive equality. When you match a file name or account that an attacker can re-case, use =~ so a query for powershell.exe still catches PowerShell.exe. The classic distractor is == , which silently misses the re-cased value and returns nothing. The same idea extends to string search: prefer the case-insensitive, term-based operators when the value's casing is not guaranteed.
Trap Using == to match a file name; it is case-sensitive, so a re-cased value like PowerShell.exe slips past a query written for powershell.exe.
- Prefer has over contains for substring-style matching
KQL has matches a whole indexed term and is fast because it uses the term index; contains matches any substring and is slower because it cannot. For hunting on command lines, file names, or URLs, reach for has or has_any first and fall back to contains only when you genuinely need a partial-token match. On a large estate the operator choice is the difference between a query that returns and one that times out.
Trap Defaulting to contains for every text match; it skips the term index and runs far slower than has on large tables.
- Defender XDR splits telemetry into product-named tables; start at the one that owns the entity
There is no single events table. Defender XDR groups telemetry by emitting product: Device* tables (DeviceProcessEvents, DeviceNetworkEvents, DeviceFileEvents, DeviceLogonEvents) from Defender for Endpoint, Email* and Url tables (EmailEvents, EmailAttachmentInfo, EmailUrlInfo, UrlClickEvents) from Defender for Office 365, Identity* tables (IdentityLogonEvents, IdentityDirectoryEvents) from Defender for Identity, and CloudAppEvents plus AAD sign-in tables from Defender for Cloud Apps and Microsoft Entra ID. The first decision in any hunt is which table owns the entity you care about, because its columns and data depend on it.
Trap Querying DeviceLogonEvents for a directory or identity sign-in; Device* tables come from Defender for Endpoint, while domain logon and directory activity live in the Identity* tables from Defender for Identity.
3 questions test this
- You have the following advanced hunting query in Microsoft Defender XDR. IdentityLogonEvents | where ActionType == 'LogonFailed' | where…
- You are using advanced hunting in Microsoft Defender XDR to investigate a potential credential theft attack. You need to correlate password…
- You use Microsoft Defender XDR advanced hunting. You need to write a KQL query that returns Kerberos and NTLM authentication activities…
- Inspect a table's columns with TableName | take 10 or the schema pane before writing the hunt
You do not have to know every column from memory. The portal's schema reference lists each table and column, and running TableName | take 10 returns a quick sample so you can see the real column names and shapes before you commit to a query. take returns arbitrary rows for sampling, not a ranked top-N; use top when you want the highest values. Inspecting first prevents the dead-end of joining or projecting a column that does not exist on that table.
Trap Treating take 10 as a top-10 ranking; take returns arbitrary rows, so for the highest counts or latest events you need top or order by.
- Cross-product hunting is the point: join or union Device, Email, and Identity tables
Advanced hunting exists to follow an attacker across products that a single-product view cannot show: from a phished mailbox (EmailEvents) to the click (UrlClickEvents) to a process on a device (DeviceProcessEvents) to a sign-in (IdentityLogonEvents). You stitch the story with join on a shared key like AccountUpn or DeviceId, or union when several tables share the same entity column. This cross-domain query surface is what distinguishes advanced hunting from running each product's own search.
- KQL join defaults to innerunique, so state kind=inner when you need every match
Unlike SQL, KQL join defaults to the innerunique flavor, which de-duplicates rows on the left table before matching. If a hunt needs every left-right pair (for example, all logons that match all of several suspicious devices), an unqualified join can silently drop rows. State join kind=inner explicitly when you want full inner-join semantics, and pick the kind (leftouter, rightsemi, anti, and so on) deliberately rather than relying on the default.
Trap Assuming an unqualified join behaves like a SQL inner join; KQL defaults to innerunique and de-duplicates the left side, so it can quietly drop matching rows.
3 questions test this
- You have a Microsoft Sentinel workspace. You need to write a KQL query for a scheduled analytics rule that matches sign-in events from…
- You have the following advanced hunting query in Microsoft Defender XDR. DeviceLogonEvents | where Timestamp > ago(1h) | where ActionType…
- You are investigating a cross-domain attack using advanced hunting in Microsoft Defender XDR. You write the following KQL query.…
- Promote a validated hunt to a custom detection rather than re-running it by hand
The lifecycle is hunt, then operationalize: refine a KQL query interactively until it reliably finds the threat with low noise, then choose Create detection rule to save it as a custom detection that re-runs on a schedule and alerts. A bare advanced hunting query is a one-time manual lookup, so a recurring need (alert whenever, continuously detect) means promote to a rule. Authoring the KQL is the hunting task; the rule's frequency, tuning, and response actions are the detections topic.
Trap Re-running an advanced hunting query by hand on a cadence for something that should be a standing custom detection rule; promotion is what makes it alert automatically.
- A query can only become a detection if it projects the columns the alert needs
For a query to promote into a usable custom detection it must return the columns Defender XDR uses to build the alert: a timestamp, an entity that maps the alert to a real asset, plus ReportId for non-endpoint tables or DeviceId for Defender for Endpoint tables so the alert ties back to the originating event. A hunt that summarizes everything away and drops these columns cannot map its alerts to an asset; project them (use take_any or arg_max to carry ReportId through an aggregation) so the alert can build.
Trap Omitting ReportId on a non-endpoint table; without it Defender XDR cannot identify the originating event, so the alert is not tied back to its source even though the rule itself still creates and runs.
- Use built-in functions, sample queries, and guided mode instead of starting blank
Advanced hunting ships helpers so you do not compose every hunt from scratch. Functions like FileProfile() enrich a file hash with prevalence and reputation in one call, Microsoft and the community publish a library of sample queries on GitHub, and guided hunting lets an analyst build a query with dropdowns instead of writing KQL. Reaching for a sample query or a function before hand-rolling a complex join is faster and less error-prone, and guided mode keeps non-KQL analysts able to hunt.
- Threat analytics answers "are we affected by this campaign", not "what is this malware"
Threat analytics is a feed of expert reports written by Microsoft security researchers that describe active campaigns, actors, and techniques, then overlay them onto your tenant's own data. So it tells you whether a named campaign is affecting you right now, with your impacted assets and your exposure, rather than giving generic malware background. The SC-200 task here is interpretation and response: read the report and act, not authoring intelligence. When a question asks which mitigations reduce exposure to a specific actor, the answer is threat analytics, not a KQL hunt.
Trap Reaching for advanced hunting to judge whether a named campaign affects you; threat analytics already overlays Microsoft intel on your tenant and shows impacted assets and exposure.
- A threat analytics report shows impacted assets, related alerts, and exposure with mitigations
Each threat analytics report turns intel into action through its tabs: an Overview and analyst report with the narrative and MITRE ATT&CK techniques, an Impacted assets view of the exact devices, users, and mailboxes with related activity, Related incidents and alerts already in your queue for that threat, and an Endpoints exposure plus Recommended actions view ranking the missing secure-configuration settings the campaign exploits. Mitigation status updates as you remediate, so the report doubles as a checklist for closing the gaps that leave you exposed.
3 questions test this
- Your company uses Microsoft Defender XDR. You review a threat analytics report and navigate to the Endpoints exposure tab to assess…
- Your company uses Microsoft Defender XDR. You review a threat analytics report for an active ransomware campaign. You need to assess the…
- You use Microsoft Defender XDR. Your security team is investigating a tracked ransomware campaign. The team needs to identify the MITRE…
- Triage by the dashboard's High-impact and Highest-exposure lenses, not a generic severity
The threat analytics dashboard summarizes the feed three ways: Latest threats (most recently published or updated), High-impact threats (greatest effect on your organization by active and resolved alert count), and Highest-exposure threats (where your configuration leaves you most exposed). Use High-impact and Highest-exposure to decide which campaign to hunt or harden first, because they are scored against your own telemetry and configuration rather than a one-size severity label. Reports also surface ready hunting queries that pivot you straight into advanced hunting.
Trap Prioritizing by a report's generic severity rating; that ignores your tenant, whereas High-impact and Highest-exposure are scored against your own affected assets and configuration gaps.
- Advanced hunting tops out near 30 days; long retention and search jobs are Sentinel
Advanced hunting queries about the last 30 days of Defender XDR data, so an investigation reaching months back belongs in Microsoft Sentinel, where long-term retention, archived log restore, and search jobs live. Keep each hunt's lookback as tight as it allows (ago(7d) returns faster than ago(30d) and is usually enough to confirm or rule out an indicator). A stem mentioning data older than 30 days, archived logs, or search jobs is pointing at Sentinel, not Defender XDR advanced hunting.
Trap Trying to hunt months-old data in Defender XDR advanced hunting; its window is about 30 days, so older investigations need Microsoft Sentinel retention and search jobs.
- KQL hunting is read-only; remediation is a separate response action
A KQL query surfaces evidence but never changes anything: it cannot isolate a device, disable a user, or delete an email. Those containment actions are taken from the incident, device, or user page in the response workflow, or are wired into a custom detection rule's automatic actions, not into the hunt itself. Knowing the read-versus-act split keeps you from expecting a hunting query to remediate and points you to the incident-response surface when the question asks how to contain.
- Network indicators (IP, URL, domain) do not support the BlockAndRemediate action
For network indicators in Microsoft Defender for Endpoint, only Allow, Audit, Block, and Warn actions are supported. A CSV import in which network indicators use BlockAndRemediate fails to import those entries; use Block instead.
Trap BlockAndRemediate is valid only for file indicators, not for IP/URL/domain network indicators.
4 questions test this
- You have Microsoft Defender for Endpoint Plan 2. You have the Custom network indicators advanced feature enabled. A security analyst…
- Your company uses Microsoft Defender for Endpoint. You prepare a CSV file that contains IP address indicators. Each indicator has the…
- Your company uses Microsoft Defender for Endpoint Plan 2. You prepare a CSV file containing 200 URL indicators. Each indicator in the CSV…
- Your company uses Microsoft Defender for Endpoint. You receive a CSV file containing 200 IP address indicators from a threat intelligence…
- For URL/domain/IP indicators, conflicting actions resolve Allow > Warn > Block
When several Defender for Endpoint URL, domain, or IP indicators target the same value, the precedence order is Allow over Warn over Block, so an Allow indicator overrides both Warn and Block.
Trap This precedence differs from file-hash indicator conflict handling, where the more secure/longer hash (SHA-256 over MD5) wins instead.
5 questions test this
- Your company uses Microsoft Defender for Endpoint. You have three separate URL/domain indicators configured for the domain contoso.com. One…
- Your company uses Microsoft Defender for Endpoint. A security analyst creates three custom indicators for the domain malicious-example.com…
- You have Microsoft Defender for Endpoint. A security analyst creates three custom indicators for the same external domain, all scoped to…
- You have Microsoft Defender for Endpoint Plan 2. Three custom indicators exist for the same domain: Indicator A has the Block action,…
- Your company uses Microsoft Defender for Endpoint. A security analyst creates three custom indicators for the same domain in the Microsoft…
References
- https://learn.microsoft.com/en-us/defender-xdr/advanced-hunting-overview
- https://learn.microsoft.com/en-us/defender-xdr/advanced-hunting-best-practices
- https://learn.microsoft.com/en-us/kusto/query/datatypes-string-operators
- https://learn.microsoft.com/en-us/defender-xdr/advanced-hunting-schema-tables
- https://learn.microsoft.com/en-us/kusto/query/join-operator
- https://learn.microsoft.com/en-us/defender-xdr/advanced-hunting-save-query
- https://learn.microsoft.com/en-us/defender-xdr/custom-detection-rules
- https://learn.microsoft.com/en-us/defender-xdr/threat-analytics