Using let Statements to Reuse Evidence
Longer investigations can become messy very quickly.
The same user appears again.
The same device appears again.
The same IP address appears again.
The same filtered evidence is needed in more than one place.
A let statement helps keep the investigation clean.
In this Agent Foskett Academy lesson, you will learn how defenders use let statements to store values, create reusable evidence sets and build clearer Microsoft Defender XDR and Microsoft Sentinel investigations.
Lesson overview
Learn how to use let statements to reuse usernames, devices, IP addresses and filtered evidence sets across a KQL investigation.
Why let statements matter
It might be a username, a device name, an IP address, a sender, a URL or a suspicious process.
A let statement lets you store that clue once, give it a useful name and reuse it throughout the investigation.
Investigation scenario
The analyst needs to check the same user across email events, URL clicks and sign-in activity.
Instead of typing the user account repeatedly, the analyst creates a reusable value with let.
Step 1 — Create a simple reusable value
- 1
- 2
- 3
- 4
- 5
let targetUser = "user@contoso.com"; SigninLogs | where TimeGenerated > ago(7d) | where UserPrincipalName == targetUser | take 100
How this works
Every time the query uses targetUser, KQL treats it as the value user@contoso.com.
If the investigation changes to another user, you only need to update one line.
Step 2 — Reuse the value across different tables
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
let targetUser = "user@contoso.com"; EmailEvents | where Timestamp > ago(7d) | where RecipientEmailAddress == targetUser | project Timestamp, RecipientEmailAddress, SenderFromAddress, Subject, DeliveryAction | sort by Timestamp desc
Step 3 — Create a reusable evidence set
- 1
- 2
- 3
- 4
- 5
- 6
- 7
let failedSignins = SigninLogs | where TimeGenerated > ago(7d) | where ResultType != 0; failedSignins | summarize FailedAttempts = count() by UserPrincipalName | sort by FailedAttempts desc
Step 4 — Reuse the same evidence in more than one way
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
let failedSignins = SigninLogs | where TimeGenerated > ago(7d) | where ResultType != 0; failedSignins | summarize FailedAttempts = count() by UserPrincipalName; failedSignins | summarize UniqueIPs = dcount(IPAddress) by UserPrincipalName | sort by UniqueIPs desc
Important investigation tip
They help make the investigation easier to explain. When the query uses names like targetUser, suspiciousDevice or failedSignins, the logic becomes easier to follow.
Step 5 — Use let in a Defender XDR timeline
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let targetUser = "user@contoso.com"; let emailActivity = EmailEvents | where Timestamp > ago(7d) | where RecipientEmailAddress == targetUser | project TimelineTime = Timestamp, EventType = "Email delivered", Account = RecipientEmailAddress, Detail = Subject; let urlActivity = UrlClickEvents | where Timestamp > ago(7d) | where AccountUpn == targetUser | project TimelineTime = Timestamp, EventType = "URL clicked", Account = AccountUpn, Detail = Url; union emailActivity, urlActivity | sort by TimelineTime asc
When to use let statements
When not to overuse let
If the query is only one or two lines, or the value is only used once, a let statement may not add much value.
What you learned
Continue your investigation
Continue learning with Connecting Tables with join, Building Investigation Timelines with KQL, KQL Threat Hunting Guide, Microsoft Defender KQL Threat Hunting Complete Guide and Microsoft Security.
Develop IT. Protect IT. GEMXIT PTY LTD | GEMXIT UK LTD