Agent Foskett Academy • Lesson 25 • Working with Dynamic Data using parse_json()

Working with Dynamic Data using parse_json()

Sometimes Microsoft security telemetry does not arrive as neat columns.
The clues may be packed inside a dynamic field, nested object or JSON-like blob.

A sign-in record may contain authentication details. An email event may contain structured authentication results. A cloud app event may include extra action data. The evidence is there, but it needs to be opened carefully.

In this Agent Foskett Academy lesson, you will learn how defenders use the KQL parse_json() function to work with dynamic data, access nested values and make complex Microsoft Defender XDR and Microsoft Sentinel telemetry easier to investigate.

Agent Foskett Academy lesson explaining how to use parse_json in KQL investigations
Lesson overview

Learn how parse_json() helps defenders open dynamic fields and pull out nested investigation evidence.

Understand dynamic data
Access nested JSON values
Create cleaner evidence columns
🎯 parse_json() helps open the evidence container.
When important values are buried inside dynamic fields, parse_json() lets you access them like investigation clues.
Review Lesson 24 →

Why parse_json() matters

Microsoft security logs often contain fields that hold more than one piece of information.

These fields may be stored as dynamic data, JSON strings or nested structures. Instead of treating the whole field as one messy block of text, parse_json() lets you convert it into a structure that KQL can query.
Open nested evidenceAccess values stored inside JSON-like fields, objects and dynamic telemetry.
Create useful columnsTurn buried properties into readable fields that can be filtered, sorted and explained.
Support deeper investigationsWork with complex Microsoft Defender XDR, Sentinel, Entra ID and cloud app telemetry.

Investigation scenario

An analyst is investigating suspicious sign-in and email activity.

Some of the useful evidence is not available as simple columns. It is stored inside fields such as AuthenticationDetails, AdditionalFields or RawEventData.

The analyst uses parse_json() to open those fields, pull out nested values and produce a cleaner investigation view.

Step 1 — Parse a dynamic field

Start by converting the field into a dynamic object so KQL can access the values inside it.
parse-dynamic-field.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
EmailEvents
| where Timestamp > ago(7d)
| extend AuthData = parse_json(AuthenticationDetails)
| project Timestamp, SenderFromAddress, RecipientEmailAddress, Subject, AuthData
| sort by Timestamp desc

Step 2 — Access a nested value

After using parse_json(), access a property by using dot notation and convert it to text with tostring().
access-nested-value.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)
| extend AuthData = parse_json(AuthenticationDetails)
| extend SPF = tostring(AuthData.SPF)
| extend DKIM = tostring(AuthData.DKIM)
| extend DMARC = tostring(AuthData.DMARC)
| project Timestamp, SenderFromAddress, SPF, DKIM, DMARC, Subject
| sort by Timestamp desc

Step 3 — Investigate sign-in authentication details

SigninLogs can contain authentication detail structures that help explain how a sign-in was completed.
signin-authentication-details.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
SigninLogs
| where TimeGenerated > ago(7d)
| extend AuthDetails = parse_json(AuthenticationDetails)
| project TimeGenerated, UserPrincipalName, AppDisplayName, ConditionalAccessStatus, AuthDetails
| sort by TimeGenerated desc

What parse_json() does

The parse_json() function interprets a string as JSON and returns dynamic data that KQL can work with.

Once the data is dynamic, you can access named properties, convert values to strings, numbers or datetimes, and use those values in filters, summaries and investigation output.
Source fieldThe original field that contains JSON-like or dynamic content.
Parsed objectThe result of parse_json(), stored in a temporary column such as AuthData or Details.
Extracted propertiesThe nested values you turn into readable columns for the investigation.

Step 4 — Filter on a parsed value

Once a nested value becomes a column, you can filter on it like any other field.
filter-parsed-values.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
EmailEvents
| where Timestamp > ago(30d)
| extend AuthData = parse_json(AuthenticationDetails)
| extend DMARC = tostring(AuthData.DMARC)
| where DMARC == "fail"
| project Timestamp, SenderFromAddress, RecipientEmailAddress, Subject, DMARC, DeliveryAction
| sort by Timestamp desc

Step 5 — Parse cloud app additional fields

AdditionalFields can contain useful context about cloud actions, devices, locations and objects involved in an event.
cloud-app-additional-fields.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
CloudAppEvents
| where Timestamp > ago(14d)
| extend Details = parse_json(AdditionalFields)
| extend ObjectName = tostring(Details.ObjectName)
| extend TargetUser = tostring(Details.TargetUser)
| project Timestamp, AccountDisplayName, Application, ActionType, ObjectName, TargetUser
| sort by Timestamp desc

Step 6 — Combine parse_json() with mv-expand

When a parsed field contains a list or array, combine parse_json() with mv-expand to review each item separately.
parse-json-with-mv-expand.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
SigninLogs
| where TimeGenerated > ago(7d)
| extend AuthDetails = parse_json(AuthenticationDetails)
| mv-expand AuthDetails
| extend AuthMethod = tostring(AuthDetails.authenticationMethod)
| extend AuthResult = tostring(AuthDetails.succeeded)
| project TimeGenerated, UserPrincipalName, AppDisplayName, AuthMethod, AuthResult
| sort by TimeGenerated desc

Investigator notes

Use parse_json() when a field contains structured data rather than simple text.

If the field is a list, you may need mv-expand after parsing it. If the field is just an inconsistent string, parse or extract() may be a better option.
Check the raw field firstLook at the original value before deciding which nested property to access.
Convert the valueUse tostring(), toint() or todatetime() when you need the parsed value in a specific format.
Keep it readableCreate clearly named columns so other analysts can understand the evidence quickly.
🎓 Agent Foskett Academy — Open the structured evidence
You now understand how to use parse_json() to access nested values and investigate dynamic Microsoft security telemetry.
Return to Academy

What you learned

In this lesson, you learned how to use the KQL parse_json() function to work with dynamic data and nested security telemetry.
Using parse_json()Convert JSON-like strings and dynamic fields into queryable objects.
Accessing nested valuesUse dot notation and type conversion functions to create clean investigation columns.
Combining with mv-expandBreak apart lists and arrays after parsing dynamic telemetry.

Continue your investigation

The next step is learning how to use extract() when you need regex-powered extraction from more flexible patterns.
Agent Foskett Academy Return to the full Academy learning path and review earlier KQL foundation lessons.
Expanding Multi-Value Data with mv-expand Review how defenders expand arrays and multi-value fields into individual investigation records.

Continue learning with Extracting Evidence with parse, Using matches regex, KQL Threat Hunting Guide and Microsoft Security.

Develop IT. Protect IT. GEMXIT PTY LTD | GEMXIT UK LTD

Working with Dynamic Data using parse_json()

Agent Foskett Academy Lesson 25 teaches defenders how to use the KQL parse_json() function to work with dynamic fields, nested values, JSON-like telemetry and structured Microsoft Defender XDR and Sentinel investigation data.

Learn KQL parse_json for Microsoft Defender XDR and Sentinel

This lesson explains how parse_json() helps defenders access nested evidence inside fields such as AdditionalFields, AuthenticationDetails, AuditData and other dynamic telemetry used in Microsoft security investigations.