Converting Values with tostring()
Microsoft security telemetry often contains values that are stored as dynamic data, numbers, arrays or nested fields.
Before those values can be searched, compared, projected or explained clearly, defenders often need to convert them into readable text.
This is where tostring() becomes useful. It allows analysts to convert a value into a string so it can be used cleanly inside an investigation query.
In this Agent Foskett Academy lesson, you will learn how defenders use the KQL tostring() function to convert evidence, work with dynamic fields and make Microsoft Defender XDR and Microsoft Sentinel results easier to understand.
Lesson overview
Learn how tostring() helps defenders convert values into readable text for cleaner KQL investigation results.
Why tostring() matters
This makes it ideal for simple investigation labels where you do not need many categories.
If case() is useful for several possible labels, iff() is useful when the question is simple and direct.
Investigation scenario
The analyst does not need a complex scoring model yet. They need simple labels that answer clear investigation questions.
By using iff() with extend, each row can be marked with a useful true-or-false style label before the evidence is reviewed.
Step 1 — Convert a sender domain from an email address
- 1
- 2
- 3
- 4
- 5
- 6
EmailEvents | where Timestamp > ago(7d) | extend SenderDomain = tostring(split(SenderFromAddress, "@")[1]) | project Timestamp, SenderFromAddress, SenderDomain, RecipientEmailAddress, Subject, DeliveryAction | order by Timestamp desc
Step 2 — Convert dynamic identity evidence
- 1
- 2
- 3
- 4
- 5
- 6
SigninLogs | where TimeGenerated > ago(7d) | extend LocationText = tostring(Location) | project TimeGenerated, UserPrincipalName, IPAddress, LocationText, ResultType, ConditionalAccessStatus | order by TimeGenerated desc
Step 3 — Convert extracted command-line evidence
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
DeviceProcessEvents | where Timestamp > ago(7d) | where FileName in~ ("powershell.exe", "pwsh.exe") | extend CommandText = tostring(ProcessCommandLine) | where CommandText has_any ("EncodedCommand", "DownloadString", "Invoke-WebRequest") | project Timestamp, DeviceName, AccountName, FileName, CommandText | order by Timestamp desc
How tostring() works
Once the value is text, defenders can search it, compare it, display it and reuse it in later parts of the investigation query.
Step 4 — Convert before filtering suspicious values
- 1
- 2
- 3
- 4
- 5
- 6
- 7
EmailEvents | where Timestamp > ago(30d) | extend SenderDomain = tostring(split(SenderFromAddress, "@")[1]) | where SenderDomain has_any ("login", "verify", "secure", "account") | project Timestamp, SenderFromAddress, SenderDomain, RecipientEmailAddress, Subject, DeliveryAction | order by Timestamp desc
tostring() compared with raw values
Common investigation uses
Common mistakes
What you learned
Related Agent Foskett Academy lessons
Continue learning with Using has_any to Find Suspicious Text, KQL Threat Hunting Guide and Microsoft Security.
Develop IT. Protect IT. GEMXIT PTY LTD | GEMXIT UK LTD