AAD Service Principal Risk Events Service Principal At Risk
Query
let query_frequency = 1h;
let query_period = 14d;
AADServicePrincipalRiskEvents
| where TimeGenerated > ago(query_period)
| summarize
ConfirmedTimeGenerated = maxif(TimeGenerated, RiskState == "confirmedCompromised"),
arg_min(TimeGenerated, *)
by Id
| where case(
isnotempty(ConfirmedTimeGenerated), false,
isempty(ActivityDateTime) and isempty(DetectedDateTime) and isnotempty(LastUpdatedDateTime) and RiskState == "dismissed", false,
//RiskDetail == "aiConfirmedSigninSafe" and RiskState == "dismissed", false,
true
)
| summarize arg_min(TimeGenerated, *) by ServicePrincipalId, RiskEventType, DetectionTimingType, RiskLevel, RiskState
| where TimeGenerated > ago(query_frequency)
| extend AlertSeverity = strcat(toupper(substring(RiskLevel, 0, 1)), substring(RiskLevel, 1))
| project
TimeGenerated,
ServicePrincipalDisplayName,
IpAddress,
Location,
OperationName,
RiskEventType,
RiskLevel,
DetectionTimingType,
RiskState,
RiskDetail,
AdditionalInfo,
Activity,
ServicePrincipalId,
AppId,
CorrelationId,
RequestId,
ActivityDateTime,
DetectedDateTime,
LastUpdatedDateTime,
Id,
AlertSeverityExplanation
This KQL (Kusto Query Language) query is designed to analyze risk events related to Azure Active Directory (AAD) service principals over a specified period. Here's a simplified breakdown of what the query does:
-
Define Timeframes:
query_frequencyis set to 1 hour, andquery_periodis set to 14 days. These are used to filter the data based on time.
-
Filter Recent Events:
- The query retrieves events from the
AADServicePrincipalRiskEventstable that have occurred within the last 14 days.
- The query retrieves events from the
-
Summarize Events:
- It summarizes the events by
Id, capturing the latest time an event was confirmed as compromised (ConfirmedTimeGenerated) and the earliest occurrence of each event.
- It summarizes the events by
-
Filter Out Certain Events:
- The query excludes events that meet specific conditions:
- If the event has a confirmed compromised time, it is excluded.
- If both
ActivityDateTimeandDetectedDateTimeare empty, butLastUpdatedDateTimeis not empty, and the risk state is "dismissed", it is excluded. - Other events are included.
- The query excludes events that meet specific conditions:
-
Further Summarization:
- It further summarizes the data by service principal ID and other risk-related attributes, ensuring only the earliest occurrence of each combination is kept.
-
Filter Recent Summarized Events:
- It filters these summarized events to include only those that occurred within the last hour.
-
Add Alert Severity:
- It creates a new field
AlertSeverityby capitalizing the first letter of theRiskLeveland appending the rest of the string.
- It creates a new field
-
Select Relevant Columns:
- Finally, it projects (selects) a set of relevant columns to be displayed in the results, including details like time generated, service principal display name, IP address, location, risk details, and more.
In essence, this query identifies and processes recent risk events related to AAD service principals, focusing on those that are not confirmed as compromised or dismissed under certain conditions, and presents them with relevant details and a calculated alert severity.
Details

Jose Sebastián Canós
Released: August 21, 2025
Tables
AADServicePrincipalRiskEvents
Keywords
AADServicePrincipalRiskEvents
Operators
letagowheresummarizemaxifarg_minbycaseisnotemptyisemptyextendstrcattouppersubstringproject