Agent Foskett Academy • Lesson 99 • Advanced KQL

Using Regular Expressions regex in KQL.

The filename did not look suspicious.

Neither did the command line.

But one pattern appeared across hundreds of events.

Agent Foskett was not looking for one exact value. He was looking for a pattern.

Agent Foskett Academy lesson using regular expressions regex in KQL for Microsoft Defender XDR
Lesson overview

Learn how to use regular expressions in KQL to match suspicious patterns, extract useful values and hunt across Microsoft Defender XDR telemetry when exact text searches are not enough.

Use matches regex for pattern matching
Extract evidence with extract()
Find suspicious command lines and URLs
Write safer and clearer regex hunts

Why regex matters in KQL

Exact text matching is useful, but attackers rarely give defenders one neat value to search for. Regex helps analysts search for patterns instead of only fixed strings.
Patterns reveal activityRegex can identify suspicious filenames, encoded commands, strange URLs and repeated naming patterns across many events.
Attackers vary their stringsA command may change by user, path, file name or domain. Regex helps hunt the structure behind the string.
Extraction makes evidence usefulFunctions such as extract() can pull domains, file extensions, encoded values or identifiers from larger telemetry fields.

The regex investigation workflow

Agent Foskett uses regex carefully: start with a clear pattern, test it against a small dataset, then apply it to the wider hunt.
1. Start with a fieldChoose the column that contains the pattern, such as ProcessCommandLine, RemoteUrl, FileName or Subject.
2. Define the patternWrite a regex that matches the structure you care about without being too broad.
3. Test with matches regexUse matches regex to return records where the field matches the suspicious pattern.
4. Extract valuesUse extract() when the goal is to capture a value from inside a larger string.
5. Keep the output readableProject the original value beside the extracted or matched value so analysts can validate the finding.
6. Tune for performanceUse time filters and normal where conditions first, then apply regex to the smaller result set.

Step 1 — Match suspicious PowerShell command patterns

Use matches regex when the command pattern matters more than a single exact phrase.
step-1-powershell-regex.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe"
| where ProcessCommandLine matches regex @"(?i)(-enc|-encodedcommand|downloadstring|invoke-webrequest|iex)"
| project Timestamp,
          DeviceName,
          AccountName,
          FileName,
          ProcessCommandLine
| order by Timestamp desc

Step 2 — Detect random-looking executable names

Regex can help identify filenames that follow suspicious naming patterns, such as long random strings ending in executable extensions.
step-2-random-filenames.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName matches regex @"(?i)^[a-z0-9]{10,}\.(exe|dll|scr)$"
| project Timestamp,
          DeviceName,
          FolderPath,
          FileName,
          InitiatingProcessFileName
| order by Timestamp desc

Step 3 — Extract domains from suspicious URLs

Use extract() to capture the part of a string that matters to the investigation.
step-3-extract-domain.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
UrlClickEvents
| where Timestamp > ago(7d)
| where isnotempty(Url)
| extend ExtractedDomain = extract(@"https?://([^/]+)", 1, Url)
| project Timestamp,
          AccountUpn,
          Url,
          ExtractedDomain,
          ActionType
| order by Timestamp desc

Step 4 — Hunt suspicious email subjects

Regex can identify phishing-style subject patterns where attackers vary wording, dates or punctuation.
step-4-email-subjects.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
EmailEvents
| where Timestamp > ago(7d)
| where Subject matches regex @"(?i)(invoice|payment|remittance|overdue).*(urgent|today|immediate)"
| project Timestamp,
          RecipientEmailAddress,
          SenderFromAddress,
          Subject,
          DeliveryAction
| order by Timestamp desc

Step 5 — Extract encoded command values

When investigating PowerShell, extract the encoded value so it can be reviewed, decoded or compared across devices.
step-5-extract-encoded-command.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any ("-enc", "-encodedcommand")
| extend EncodedValue = extract(@"(?i)-(enc|encodedcommand)\s+([A-Za-z0-9+/=]{20,})", 2, ProcessCommandLine)
| where isnotempty(EncodedValue)
| project Timestamp,
          DeviceName,
          AccountName,
          EncodedValue,
          ProcessCommandLine

Step 6 — Clean strings with replace_regex()

Use replace_regex() when you want to normalise noisy values before grouping or comparing them.
step-6-replace-regex.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe"
| extend NormalisedCommand = replace_regex(ProcessCommandLine, @"(?i)C:\\Users\\[^\\]+", @"C:\Users\USER")
| project Timestamp,
          DeviceName,
          AccountName,
          ProcessCommandLine,
          NormalisedCommand
| order by Timestamp desc

Regex patterns defenders should recognise

Case-insensitive matchingUse (?i) when the same suspicious term may appear in different letter casing.
Character classesUse patterns such as [a-z0-9] when looking for structured values such as random file names or tokens.
Capture groupsUse brackets in extract() to capture a specific value from inside a larger string.
AnchorsUse ^ and $ when the whole field should match the pattern rather than only part of it.
Escaping charactersBackslashes, dots and brackets can have special meanings, so escape them when you need literal matching.
Limit broad matchingA regex that matches everything is not a useful hunt. Make the pattern specific enough to support the investigation.

Real-world investigation

The strange patternSeveral devices created executable files with different names, but the names all followed the same random-looking structure.
The command linePowerShell commands varied by path and user profile, but regex revealed the same encoded command pattern.
The URL clueAgent Foskett extracted domains from clicked URLs and grouped the results by user and action.
The phishing subjectEmail subjects were not identical, but regex matched the payment-themed wording and urgency pattern.
The outcomeThe investigation moved from searching for isolated strings to proving a repeated pattern across endpoint, email and URL telemetry.
The lessonRegex is powerful when it is used with purpose, a narrow dataset and a clear investigation question.

Investigation checklist

Filter before regexUse Timestamp, table-specific filters and known indicators before applying regular expressions.
Test on small resultsValidate the pattern with take or a short time window before running it across larger data.
Prefer clarityA readable regex that analysts understand is usually better than a clever regex nobody can maintain.
Project the matched fieldAlways show the original column so the analyst can confirm the pattern matched what they expected.
Extract when usefulUse extract() when a pattern contains a value that should become its own investigation column.
Document the intentAdd comments or clear variable names when regex becomes part of a reusable hunting query.

Related Agent Foskett Academy lessons

Using mv-apply in KQLAnalyse multi-value fields with greater control during Defender XDR investigations.
Using mv-expand in KQLSplit arrays and multi-value fields into individual records.
Working with Dynamic Data and JSONExtract values from JSON and dynamic fields before pattern matching.
Using let StatementsStore regex patterns and hunting parameters in reusable variables.
Optimising KQL Queries for PerformanceUse regex efficiently by filtering data before expensive pattern matching.
Building an IOC HuntApply pattern matching to investigate indicators across Microsoft Defender XDR.

Coming next

Lesson 100 — Building Reusable Hunting QueriesNext, Agent Foskett Academy brings the Advanced KQL block together by building reusable hunting queries from let statements, joins, dynamic data, regex and investigation-focused outputs.
Why this mattersRegex finds patterns, but reusable hunting queries help teams run consistent investigations again and again.

Final thought

Regex is not magic. It is a way to describe the shape of suspicious evidence.
Agent Foskett mindsetWhen exact values keep changing, search for the pattern that stays the same.
The pattern told the storyThe strings changed, but the attacker behaviour followed the same structure.
Develop IT. Protect IT.GEMXIT PTY LTD | GEMXIT UK LTD

Using Regular Expressions regex in KQL

Agent Foskett Academy Lesson 99 teaches defenders how to use regular expressions and regex in KQL to match suspicious patterns across Microsoft Defender XDR telemetry.

Learn regex for Microsoft Defender XDR threat hunting

Regular expressions help Microsoft security analysts identify suspicious command lines, URLs, filenames, email subjects and encoded values when exact string matching is not enough.

KQL regex tutorial for Microsoft security analysts

This lesson explains matches regex, extract(), replace_regex() and practical Defender XDR investigation patterns for endpoint, email and URL telemetry.