Query Details

Purview DLP Endpoint Alert Info

Query

let alert_id = "<<<>>>";
let query_period = 1d;
CloudAppEvents
| where Timestamp > ago(query_period)
| where ActionType in ("AlertTriggered", "AlertUpdated") and tostring(RawEventData["AlertId"]) == alert_id
| summarize arg_max(Timestamp, *)
| extend
    AlertId = tostring(RawEventData["AlertId"]),
    Data = todynamic(tostring(RawEventData["Data"]))
| extend
    UserPrincipalName = tolower(tostring(Data["f3u"])),
    Severity = tostring(Data["sev"]),
    Workload = tostring(Data["wl"]),
    SensitiveInformationContentType = split(tostring(Data["sict"]), ";"),
    SensitiveInformationTypeMatchInfo = split(tostring(Data["sitmi"]), ";"),
    PolicyId = tostring(Data["dpid"]),
    PolicyName = tostring(Data["dpn"]),
    RuleId = tostring(Data["drid"]),
    RuleName = tostring(Data["drn"]),
    ProtectionMode = tostring(Data["enmd"]),
    ProtectionActions = split(tostring(Data["dact"]), ", "),
    ObjectName = tostring(Data["von"]),
    Operation = tostring(Data["eop"]),
    OperationApp = tostring(Data["app"]),
    ObjectFilePath = tostring(Data["ofph"]),
    FileSize = tostring(Data["efs"]),
    TargetFilePath = tostring(Data["tfph"]),
    TargetDomain = tostring(Data["tdmn"]),
    RemovableMassStorageSerialNumber = tostring(Data["rmsn"]),
    RMSEncrypted = tobool(Data["rmse"]),
    TargetPrinterName = tostring(Data["pn"]),
    DeviceId = tostring(Data["mddid"]),
    DeviceName = tostring(Data["dn"]),
    ClientIP = tostring(Data["ecip"]),
    AuxiliarTimestamp = todatetime(Data["ts"])
| where Workload == "Endpoint" and tostring(RawEventData["Category"]) == "DataLossPrevention"
| project
    Timestamp,
    Application,
    ActionType,
    AlertId,
    UserPrincipalName,
    Severity,
    Workload,
    SensitiveInformationContentType,
    SensitiveInformationTypeMatchInfo,
    PolicyId,
    PolicyName,
    RuleId,
    RuleName,
    ProtectionMode,
    ProtectionActions,
    ObjectName,
    Operation,
    OperationApp,
    ObjectFilePath,
    FileSize,
    TargetFilePath,
    TargetDomain,
    RemovableMassStorageSerialNumber,
    RMSEncrypted,
    TargetPrinterName,
    DeviceId,
    DeviceName,
    ClientIP,
    AuxiliarTimestamp,
    AlertTriggered_RawEventData = RawEventData,
    AlertTriggered_ReportId = ReportId
| join hint.strategy=shuffle kind=leftouter (
    CloudAppEvents
    | where Timestamp > ago(query_period)
    | where Application == "Microsoft 365" and RawEventData["Workload"] == "Endpoint" and RawEventData has_all ("PolicyMatchInfo", "PolicyId", "RuleId")
    | project
        CreationTime = todatetime(RawEventData["CreationTime"]),
        DeviceId = tostring(RawEventData["MDATPDeviceId"]),
        Operation = tostring(RawEventData["Operation"]),
        OperationApp = tostring(RawEventData["Application"]),
        MatchedPolicies = RawEventData["MatchedPolicies"],
        ObjectFilePath = tostring(RawEventData["ObjectId"]),
        TargetFilePath = tostring(RawEventData["TargetFilePath"]),
        DlpOriginalFilePath = tostring(RawEventData["DlpOriginalFilePath"]),
        OriginatingDomain = tostring(RawEventData["OriginatingDomain"]),
        Justification = tostring(RawEventData["Justification"]),
        RemovableMediaDeviceAttributes = RawEventData["RemovableMediaDeviceAttributes"],
        ParentArchiveHash = tostring(RawEventData["ParentArchiveHash"]),
        PreviousFileName = tostring(RawEventData["PreviousFileName"]),
        FileType = tostring(RawEventData["FileType"]),
        FileExtension = tostring(RawEventData["FileExtension"]),
        Sha1 = tostring(RawEventData["Sha1"]),
        Sha256 = tostring(RawEventData["Sha256"]),
        SourceLocationType = toint(RawEventData["SourceLocationType"]),
        DestinationLocationType = toint(RawEventData["DestinationLocationType"]),
        //Hidden = tostring(RawEventData["Hidden"]),
        UserType = toint(RawEventData["UserType"]),
        EndpointOperation_RawEventData = RawEventData,
        EndpointOperation_ReportId = ReportId
    | mv-expand MatchedPolicy = iff(array_length(MatchedPolicies) > 0, MatchedPolicies, pack_array(EndpointOperation_RawEventData["PolicyMatchInfo"]))
    | extend
        DlpOriginalFilePath = iff(DlpOriginalFilePath == ObjectFilePath, "", DlpOriginalFilePath),
        PolicyId = tostring(MatchedPolicy["PolicyId"]),
        RuleId = tostring(MatchedPolicy["RuleId"])
    | project-away MatchedPolicies, MatchedPolicy
    | extend AuxiliarTimestamp = bin(CreationTime, 1m)
    | summarize arg_min(CreationTime, *) by AuxiliarTimestamp, DeviceId, Operation, OperationApp, ObjectFilePath, TargetFilePath, PolicyId, RuleId
    ) on AuxiliarTimestamp, DeviceId, Operation, OperationApp, ObjectFilePath, TargetFilePath, PolicyId, RuleId
| project-away AuxiliarTimestamp, DeviceId1, Operation1, OperationApp1, ObjectFilePath1, PolicyId1, RuleId1, TargetFilePath1
| mv-apply SensitiveInfoTypeData = EndpointOperation_RawEventData["SensitiveInfoTypeData"] on (
    summarize SensitiveInformation = make_list(bag_remove_keys(SensitiveInfoTypeData, dynamic(["SensitiveInformationDetailedClassificationAttributes"])))
    )

Explanation

This query is designed to analyze and correlate cloud application events related to data loss prevention (DLP) alerts within a specified time frame (1 day). Here's a simplified breakdown of what the query does:

  1. Define Parameters:

    • alert_id: A specific alert identifier to filter the events.
    • query_period: The time range for the query, set to 1 day.
  2. Filter Cloud Application Events:

    • It retrieves events from the CloudAppEvents table where the timestamp is within the last day.
    • It focuses on events where the action type is either "AlertTriggered" or "AlertUpdated" and matches the specified alert_id.
  3. Summarize and Extend Data:

    • It selects the most recent event (arg_max) for each alert and extracts various details from the raw event data, such as user information, severity, policy details, and file operations.
  4. Filter for Specific Workload:

    • It further filters the events to include only those related to the "Endpoint" workload and categorized as "DataLossPrevention".
  5. Project Relevant Fields:

    • It selects and organizes specific fields to be included in the output, such as user details, policy information, file paths, and device information.
  6. Join with Additional Events:

    • It performs a left outer join with another set of CloudAppEvents to correlate additional details related to endpoint operations, such as matched policies and file attributes.
  7. Summarize Sensitive Information:

    • It processes and summarizes sensitive information type data, excluding detailed classification attributes, to provide a list of sensitive information involved in the events.

Overall, the query aims to provide a comprehensive view of DLP-related alerts and operations, correlating them with additional endpoint data to enhance understanding and analysis of potential data loss incidents.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: May 7, 2025

Tables

CloudAppEvents

Keywords

CloudAppEventsTimestampActionTypeRawEventDataAlertIdDataUserPrincipalNameSeverityWorkloadSensitiveInformationContentTypeSensitiveInformationTypeMatchInfoPolicyIdPolicyNameRuleIdRuleNameProtectionModeProtectionActionsObjectNameOperationOperationAppObjectFilePathFileSizeTargetFilePathTargetDomainRemovableMassStorageSerialNumberRMSEncryptedTargetPrinterNameDeviceIdDeviceNameClientIPAuxiliarTimestampApplicationMicrosoft365PolicyMatchInfoCreationTimeMatchedPoliciesDlpOriginalFilePathOriginatingDomainJustificationRemovableMediaDeviceAttributesParentArchiveHashPreviousFileNameFileTypeFileExtensionSha1Sha256SourceLocationTypeDestinationLocationTypeUserTypeSensitiveInfoTypeDataSensitiveInformation

Operators

letin==summarizearg_maxextendtostringtodynamictolowersplittobooltodatetimeprojectjoinhint.strategykindleftouterhas_allmv-expandiffarray_lengthpack_arraybinarg_minbyproject-awaymv-applymake_listbag_remove_keysdynamic

Actions

GitHub