Skip to content

DLP Event Extraction for Copilot Location

Parent: Deny Event Correlation Report


Overview

Microsoft Purview DLP supports a dedicated Microsoft 365 Copilot and Copilot Chat policy location. This guide covers extracting DLP events that match this location for correlation with CopilotInteraction deny events.


DLP Policy Location

Copilot-Specific Policy Location

When creating DLP policies in Microsoft Purview, the "Microsoft 365 Copilot and Copilot Chat" location enables:

  • Sensitivity label-based blocking - Prevent Copilot from accessing files with specific labels
  • Prompt content inspection - Detect SITs in user prompts
  • Response blocking - Block responses containing sensitive data

Policy Configuration Reference

Policy Action When It Triggers Audit Event
Block User prompt contains SIT or requests restricted content DlpRuleMatch
Warn User warned but can proceed DlpRuleMatch
Override User provided justification DlpRuleMatch with override

DLP Event Schema

DlpRuleMatch Audit Record

{
  "RecordType": 55,
  "Operation": "DlpRuleMatch",
  "Workload": "MicrosoftCopilot",
  "UserId": "user@contoso.com",
  "PolicyDetails": [{
    "PolicyId": "guid",
    "PolicyName": "Block NPI in Copilot",
    "Rules": [{
      "RuleName": "SSN Detection",
      "Actions": ["BlockAccess"],
      "Severity": "High"
    }]
  }],
  "SensitiveInfoTypeData": [{
    "SensitiveInfoTypeId": "a44669fe-0d48-453d-a9b1-2cc83f2cba77",
    "SensitiveInfoTypeName": "U.S. Social Security Number (SSN)",
    "Count": 1,
    "Confidence": 85
  }],
  "ExceptionInfo": null
}

Prerequisites

Entra ID App Registration

Before running the extraction script, configure an Entra ID App Registration with Exchange Online access:

Requirement Value
App Registration Create in Entra ID > App registrations
API Permission Office 365 Exchange Online > Application > Exchange.ManageAsApp
Admin Consent Required (tenant admin)
Entra Role Purview Audit Reader or Purview Compliance Admin
Key Vault Store client secret in Azure Key Vault

PowerShell Extraction Script

Daily DLP Export with Entra ID Authentication

The modernized script uses the DECClient.psm1 shared module for secure authentication. Credentials are retrieved from Azure Key Vault — no hardcoded secrets.

#Requires -Version 7.0
#Requires -Modules @{ ModuleName="ExchangeOnlineManagement"; ModuleVersion="3.0.0" }

<#
.SYNOPSIS
    Exports DLP events for the Copilot policy location.
.DESCRIPTION
    Uses Entra ID service principal authentication via DECClient module.
    Retrieves credentials from Azure Key Vault — no hardcoded secrets.
.PARAMETER TenantId
    Entra ID tenant ID for service principal authentication.
.PARAMETER ClientId
    App Registration client ID with Exchange.ManageAsApp permission.
.PARAMETER KeyVaultName
    Azure Key Vault containing the service principal credentials.
.PARAMETER DaysBack
    Days of data to retrieve (default: 1, max: 90).
.PARAMETER OutputPath
    Path for exported file.
.PARAMETER OutputFormat
    Export format: CSV or JSON (default: CSV).
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$TenantId,
    [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$ClientId,
    [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$KeyVaultName,
    [ValidateNotNullOrEmpty()][string]$CertificateThumbprint,
    [ValidateRange(1, 90)][int]$DaysBack = 1,
    [ValidateScript({ Test-Path (Split-Path $_) })][string]$OutputPath,
    [ValidateSet('CSV','JSON')][string]$OutputFormat = 'CSV'
)

$ErrorActionPreference = 'Stop'

# Import shared authentication module
Import-Module "$PSScriptRoot/private/DECClient.psm1" -Force

# Connect to Exchange Online via Entra ID service principal
$connectParams = @{
    TenantId     = $TenantId
    ClientId     = $ClientId
    KeyVaultName = $KeyVaultName
}
if ($CertificateThumbprint) {
    $connectParams['CertificateThumbprint'] = $CertificateThumbprint
}
$connectResult = Connect-DECExchangeOnline @connectParams
if ($connectResult.Status -ne 'Success') {
    Write-Error "Connection failed: $($connectResult.Message)"
    return
}

# Search for DlpRuleMatch events
$startDate = (Get-Date).AddDays(-$DaysBack).Date
$endDate   = (Get-Date).Date
$allDlpEvents = @()
$sessionId = [Guid]::NewGuid().ToString()

do {
    $results = Search-UnifiedAuditLog `
        -RecordType DlpRuleMatch `
        -StartDate $startDate `
        -EndDate $endDate `
        -SessionId $sessionId `
        -SessionCommand ReturnLargeSet `
        -ResultSize 5000

    if ($results) {
        $allDlpEvents += $results
        Write-Verbose "Retrieved $($allDlpEvents.Count) events..."
    }
} while ($results.Count -eq 5000)

Write-Host "Total DLP events: $($allDlpEvents.Count)"

# Filter for Copilot-related events
$copilotDlpEvents = $allDlpEvents | ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json

    $isCopilotRelated = (
        $auditData.Workload -eq "MicrosoftCopilot" -or
        $auditData.Workload -match "Copilot" -or
        ($auditData.PolicyDetails | Where-Object { $_.PolicyName -match "Copilot" })
    )

    if ($isCopilotRelated) {
        $policyNames = ($auditData.PolicyDetails |
            ForEach-Object { $_.PolicyName }) -join "; "
        $ruleNames = ($auditData.PolicyDetails.Rules |
            ForEach-Object { $_.RuleName }) -join "; "
        $actions = ($auditData.PolicyDetails.Rules.Actions |
            Select-Object -Unique) -join "; "
        $sitMatches = ($auditData.SensitiveInfoTypeData | ForEach-Object {
            "$($_.SensitiveInfoTypeName) (Count: $($_.Count), Confidence: $($_.Confidence)%)"
        }) -join "; "

        [PSCustomObject]@{
            Timestamp          = $_.CreationDate
            UserId             = $auditData.UserId
            Workload           = $auditData.Workload
            PolicyNames        = $policyNames
            RuleNames          = $ruleNames
            Actions            = $actions
            SensitiveInfoTypes = $sitMatches
            Severity           = ($auditData.PolicyDetails.Rules |
                Select-Object -ExpandProperty Severity -First 1)
            HasOverride        = ($null -ne $auditData.ExceptionInfo)
            RawAuditData       = $_.AuditData
        }
    }
}

Write-Host "Copilot DLP events found: $($copilotDlpEvents.Count)"

# Export results
if ($OutputFormat -eq 'JSON') {
    $copilotDlpEvents | ConvertTo-Json -Depth 10 |
        Set-Content -Path $OutputPath -Encoding UTF8
} else {
    $copilotDlpEvents | Export-Csv -Path $OutputPath -NoTypeInformation
}
Write-Host "Exported to: $OutputPath"

Deprecated: Legacy Authentication

The v1.x script used interactive Connect-ExchangeOnline with user credentials. This approach does not support unattended automation and does not meet FSI security standards. Use the Entra ID service principal pattern shown above.


Correlation with CopilotInteraction

DLP events may precede or coincide with CopilotInteraction events. Use these correlation strategies:

Timestamp Window Correlation

# In Power BI or offline processing
# Join DLP and CopilotInteraction events within ±5 minute window

$correlatedEvents = foreach ($dlp in $copilotDlpEvents) {
    $matchingCopilot = $copilotDenyEvents | Where-Object {
        $_.UserId -eq $dlp.UserId -and
        [Math]::Abs(($_.Timestamp - $dlp.Timestamp).TotalMinutes) -le 5
    }

    if ($matchingCopilot) {
        [PSCustomObject]@{
            CorrelationId = [Guid]::NewGuid()
            DlpTimestamp = $dlp.Timestamp
            CopilotTimestamp = $matchingCopilot.Timestamp
            UserId = $dlp.UserId
            DlpPolicy = $dlp.PolicyNames
            DlpAction = $dlp.Actions
            CopilotDenyReason = $matchingCopilot.DenyReason
            AgentName = $matchingCopilot.AgentName
        }
    }
}

Correlation Categories

Scenario DLP Event CopilotInteraction Event Meaning
Policy Block Present Status=failure DLP blocked content access
Prompt Scan Present No deny DLP scanned but allowed
Agent Guardrail Absent Status=failure Agent-level block, not DLP
XPIA/Jailbreak Absent XPIA=true Security event, not data governance

Output Schema

The exported CSV includes:

Column Type Description
Timestamp DateTime Event occurrence time
UserId String User principal name
Workload String Microsoft service (MicrosoftCopilot)
PolicyNames String DLP policies that matched
RuleNames String Specific rules triggered
Actions String Block, Warn, or Override
SensitiveInfoTypes String SITs detected with confidence
Severity String Low, Medium, High
HasOverride Boolean User overrode policy
RawAuditData JSON Full audit record

Common DLP Patterns for FSI

Pattern 1: NPI Protection

PolicyName: "Block NPI in Microsoft 365 Copilot"
SensitiveInfoTypes: U.S. Social Security Number, U.S. Bank Account Number
Action: Block

Pattern 2: Confidential Label Restriction

PolicyName: "Restrict Confidential Content from Copilot"
Condition: Sensitivity Label = "Confidential - NPI"
Action: Block

Pattern 3: Customer Data Warning

PolicyName: "Warn on Customer Data in Copilot"
SensitiveInfoTypes: Customer ID, Account Number (Custom SIT)
Action: Warn with justification

Next Steps


FSI Agent Governance Framework v1.2.51 - February 2026