Query Details

Multiple Microsoft Entra Threat Intelligence

Query

let query_frequency = 5m;
let query_period = 2d;
AADUserRiskEvents
| where TimeGenerated > ago(query_period)
| where Source == "IdentityProtection" and RiskEventType == "investigationsThreatIntelligence"
| summarize FirstTimeGenerated = min(TimeGenerated), arg_max(TimeGenerated, *) by Id
| where FirstTimeGenerated > ago(query_frequency)
| project
    //TimeGenerated,
    ActivityDateTime,
    DetectedDateTime,
    Source,
    Activity,
    DetectionTimingType,
    UserDisplayName,
    UserPrincipalName,
    UserId,
    IpAddress,
    RequestId,
    CorrelationId,
    TokenIssuerType,
    RiskEventType,
    RiskDetail,
    RiskLevel,
    RiskState,
    AdditionalInfo,
    Id
| extend AltAlertLink = strcat("https://entra.microsoft.com/#blade/Microsoft_AAD_IAM/RiskDetectionsBlade/riskState~/[]/userId/", UserId, "/riskLevel/[]/daysBack/90")// Someone wrote "90s" incorrectly in Defender XDR portal
| join kind=leftouter (
    SecurityAlert
    | where ProviderName == "IPC" and ProductName == "Azure Active Directory Identity Protection"// and AlertType == ?
    | summarize arg_max(TimeGenerated, *) by VendorOriginalId
    | project
        AlertName,
        AlertSeverity,
        Description,
        AlertStatus = Status,
        Entities,
        ExtendedProperties,
        VendorName,
        ProviderName,
        ProductName,
        ProductComponentName,
        RemediationSteps,
        Tactics,
        Techniques,
        SubTechniques,
        VendorOriginalId,
        SystemAlertId,
        CompromisedEntity,
        AlertLink
    ) on $left.Id == $right.VendorOriginalId
| extend AlertLink = coalesce(AlertLink, AltAlertLink)
| as _Events
| lookup kind=leftouter (
    SigninLogs
    | where TimeGenerated > ago(query_period)
    //| where RiskEventTypes_V2 has "azureADThreatIntel"
    | where OriginalRequestId in (toscalar(_Events | summarize make_list(RequestId)))
    | extend TimeReceived = _TimeReceived
    | summarize arg_max(TimeReceived, *) by OriginalRequestId
    | project
        TimeGenerated,
        CreatedDateTime,
        Type,
        //UserDisplayName,
        //UserPrincipalName,
        //UserId,
        AlternateSignInName,
        SignInIdentifier,
        UserType,
        IPAddress,
        AutonomousSystemNumber,
        Location,
        NetworkLocationDetails,
        ResultType,
        ResultSignature,
        ResultDescription,
        ClientAppUsed,
        AppDisplayName,
        ResourceDisplayName,
        DeviceDetail,
        UserAgent,
        Status,
        MfaDetail,
        AuthenticationContextClassReferences,
        AuthenticationDetails,
        AuthenticationProcessingDetails,
        AuthenticationProtocol,
        AuthenticationRequirement,
        AuthenticationRequirementPolicies,
        SessionLifetimePolicies,
        //TokenIssuerType,
        IncomingTokenType,
        TokenProtectionStatusDetails,
        ConditionalAccessStatus,
        ConditionalAccessPolicies,
        SignInLogs_RiskDetail = RiskDetail,
        RiskEventTypes_V2,
        RiskLevelAggregated,
        RiskLevelDuringSignIn,
        SignInLogs_RiskState = RiskState,
        HomeTenantId,
        ResourceTenantId,
        CrossTenantAccessType,
        AppId,
        ResourceIdentity,
        UniqueTokenIdentifier,
        SessionId,
        OriginalRequestId//,
        //CorrelationId
    ) on $left.RequestId == $right.OriginalRequestId
| where case(
    //AlertStatus == "Resolved" and tostring(todynamic(ExtendedProperties)["State"]) == "Closed", false,
    //RiskState == "dismissed" and RiskDetail == "aiConfirmedSigninSafe", false,
    RiskState == "remediated" and RiskDetail == "userChangedPasswordOnPremises", false,
    true
    )
| project
    //TimeGenerated,
    ActivityDateTime,
    DetectedDateTime,
    Source,
    Activity,
    DetectionTimingType,
    UserDisplayName,
    UserPrincipalName,
    UserId,
    IpAddress,
    RequestId,
    CorrelationId,
    TokenIssuerType,
    RiskEventType,
    RiskDetail,
    RiskLevel,
    RiskState,
    AdditionalInfo,
    Id,
    AlertName,
    AlertSeverity,
    Description,
    AlertStatus,
    Entities,
    ExtendedProperties,
    VendorName,
    ProviderName,
    ProductName,
    ProductComponentName,
    RemediationSteps,
    Tactics,
    Techniques,
    SubTechniques,
    VendorOriginalId,
    SystemAlertId,
    CompromisedEntity,
    AlertLink,
    TimeGenerated,
    CreatedDateTime,
    Type,
    //UserDisplayName,
    //UserPrincipalName,
    //UserId,
    AlternateSignInName,
    SignInIdentifier,
    UserType,
    IPAddress,
    AutonomousSystemNumber,
    Location,
    NetworkLocationDetails,
    ResultType,
    ResultSignature,
    ResultDescription,
    ClientAppUsed,
    AppDisplayName,
    ResourceDisplayName,
    DeviceDetail,
    UserAgent,
    Status,
    MfaDetail,
    AuthenticationContextClassReferences,
    AuthenticationDetails,
    AuthenticationProcessingDetails,
    AuthenticationProtocol,
    AuthenticationRequirement,
    AuthenticationRequirementPolicies,
    SessionLifetimePolicies,
    //TokenIssuerType,
    IncomingTokenType,
    TokenProtectionStatusDetails,
    ConditionalAccessStatus,
    ConditionalAccessPolicies,
    SignInLogs_RiskDetail,
    RiskEventTypes_V2,
    RiskLevelAggregated,
    RiskLevelDuringSignIn,
    SignInLogs_RiskState,
    HomeTenantId,
    ResourceTenantId,
    CrossTenantAccessType,
    AppId,
    ResourceIdentity,
    UniqueTokenIdentifier,
    SessionId//,
    //OriginalRequestId,
    //CorrelationId

Explanation

This query is designed to analyze and correlate user risk events and security alerts related to Azure Active Directory Identity Protection over a specified period. Here's a simplified breakdown of what the query does:

  1. Define Time Periods:

    • query_frequency is set to 5 minutes.
    • query_period is set to 2 days.
  2. Filter Risk Events:

    • It retrieves data from the AADUserRiskEvents table for the last 2 days.
    • Filters events where the source is "IdentityProtection" and the risk event type is "investigationsThreatIntelligence".
    • Summarizes the data to find the first and most recent occurrence of each event by Id.
  3. Filter Recent Events:

    • Further filters to include only those events that first occurred within the last 5 minutes.
  4. Project Relevant Columns:

    • Selects specific columns to include in the output, such as user details, risk details, and event identifiers.
  5. Create Alternative Alert Link:

    • Constructs a URL for each event to view more details in the Microsoft Entra portal.
  6. Join with Security Alerts:

    • Performs a left outer join with the SecurityAlert table to correlate risk events with security alerts.
    • Filters alerts from the "IPC" provider and "Azure Active Directory Identity Protection" product.
    • Projects relevant alert details.
  7. Ensure Alert Link Availability:

    • Uses the alternative alert link if the original alert link is not available.
  8. Join with Sign-in Logs:

    • Looks up additional sign-in details from the SigninLogs table for the last 2 days.
    • Matches events based on the RequestId.
  9. Filter Out Remediated Events:

    • Excludes events where the risk state is "remediated" and the risk detail indicates the user changed their password on-premises.
  10. Final Projection:

    • Projects a comprehensive set of columns from the joined data, including user, risk, alert, and sign-in details.

In summary, this query identifies recent user risk events, correlates them with security alerts, and enriches them with sign-in details, while filtering out events that have been remediated by a password change.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: September 18, 2025

Tables

AADUserRiskEventsSecurityAlertSigninLogs

Keywords

AADUserRiskEventsSecurityAlertSigninLogsUserUserIdUserDisplayNameUserPrincipalNameRiskEventTypeRiskDetailRiskLevelRiskStateIpAddressRequestIdCorrelationIdTokenIssuerTypeAlertNameAlertSeverityDescriptionAlertStatusEntitiesExtendedPropertiesVendorNameProviderNameProductNameProductComponentNameRemediationStepsTacticsTechniquesSubTechniquesVendorOriginalIdSystemAlertIdCompromisedEntityAlertLinkTimeGeneratedCreatedDateTimeTypeAlternateSignInNameSignInIdentifierUserTypeIPAddressAutonomousSystemNumberLocationNetworkLocationDetailsResultTypeResultSignatureResultDescriptionClientAppUsedAppDisplayNameResourceDisplayNameDeviceDetailUserAgentStatusMfaDetailAuthenticationContextClassReferencesAuthenticationDetailsAuthenticationProcessingDetailsAuthenticationProtocolAuthenticationRequirementAuthenticationRequirementPoliciesSessionLifetimePoliciesIncomingTokenTypeTokenProtectionStatusDetailsConditionalAccessStatusConditionalAccessPoliciesRiskEventTypes_V2RiskLevelAggregatedRiskLevelDuringSignInHomeTenantIdResourceTenantIdCrossTenantAccessTypeAppIdResourceIdentityUniqueTokenIdentifierSessionId

Operators

letagowheresummarizeminarg_maxbyprojectextendstrcatjoinoncoalesceaslookuptoscalarmake_listcasetostringtodynamic

Actions