Microsoft continues to strengthen its security ecosystem with a significant enhancement to Microsoft Purview's Data Loss Prevention (DLP) capabilities. The new Graph API infrastructure allows organizations to seamlessly export DLP event data to enrich Microsoft Defender alerts, creating a more comprehensive security monitoring experience. This integration bridges the gap between data protection and threat detection, providing security teams with richer context when investigating potential incidents.
Understanding the Enhanced Integration Context
Microsoft Purview DLP has long been a cornerstone of data protection strategies for organizations worldwide. However, security teams often struggled with siloed information where DLP events existed separately from broader security alerts in Microsoft Defender. This separation created blind spots and required manual correlation of events across different security tools.
The enhanced Graph API infrastructure addresses this challenge by providing a standardized, programmatic way to export DLP event data and correlate it with Defender alerts. This integration is part of Microsoft's broader strategy to create a unified security operations center (SOC) experience across its security portfolio.
Currently in General Availability for Worldwide Standard Multi-Tenant environments, this enhancement represents a significant step forward in security data integration. Organizations can now leverage the wealth of DLP event data to provide additional context to security incidents, improving both detection accuracy and response times.
The Challenge: Fragmented Security Data
Before this enhancement, security teams faced several critical challenges:
- Data Silos: DLP events were confined to the Purview compliance portal, while security alerts lived in Microsoft Defender
- Manual Correlation: Analysts had to manually cross-reference DLP events with security incidents, consuming valuable time
- Incomplete Context: Security investigations lacked crucial data protection context that could indicate the severity or scope of an incident
- Limited API Access: Existing API endpoints provided limited DLP event data, making automated integration difficult
- Inconsistent Reporting: Different data formats and structures across security tools hindered comprehensive reporting
These challenges often resulted in delayed incident response, missed correlations between data exfiltration attempts and security breaches, and an incomplete understanding of the organization's security posture.
Implementing DLP Event Data Export via Graph API
Prerequisites and Permissions
Before implementing the enhanced Graph API integration, ensure your environment meets the following requirements:
- Microsoft 365 E5 or equivalent licensing with Purview DLP
- Microsoft Defender for Office 365 or Microsoft 365 Defender
- Appropriate Graph API permissions (SecurityEvents.Read.All, SecurityAlert.ReadWrite.All)
- PowerShell 7.0 or later with Microsoft.Graph module
Step 1: Configure Graph API Application Registration
First, register an application in Azure AD with the necessary permissions to access both DLP events and Defender alerts:
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All"
# Create application registration
$appRegistration = New-MgApplication -DisplayName "DLP-Defender Integration" -SignInAudience "AzureADMyOrg"
# Add required API permissions
$requiredResourceAccess = @(
@{
ResourceAppId = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
ResourceAccess = @(
@{
Id = "7438b122-aefc-4978-80ed-43db9fcc7715" # SecurityEvents.Read.All
Type = "Role"
},
@{
Id = "ed4fca05-be46-441f-9803-1873825f8fdb" # SecurityAlert.ReadWrite.All
Type = "Role"
},
@{
Id = "45cc0394-e837-488b-a098-1918f48d186c" # SecurityIncident.ReadWrite.All
Type = "Role"
}
)
}
)
Update-MgApplication -ApplicationId $appRegistration.Id -RequiredResourceAccess $requiredResourceAccess
# Create service principal
$servicePrincipal = New-MgServicePrincipal -AppId $appRegistration.AppId
Write-Host "Application ID: $($appRegistration.AppId)"
Write-Host "Service Principal ID: $($servicePrincipal.Id)"
Step 2: Create Client Secret and Grant Admin Consent
# Create client secret
$passwordCredential = @{
DisplayName = "DLP-Defender-Secret"
EndDateTime = (Get-Date).AddYears(1)
}
$clientSecret = Add-MgApplicationPassword -ApplicationId $appRegistration.Id -PasswordCredential $passwordCredential
Write-Host "Client Secret: $($clientSecret.SecretText)" -ForegroundColor Yellow
Write-Host "Store this secret securely - it won't be shown again!" -ForegroundColor Red
# Note: Admin consent must be granted through Azure Portal or via PowerShell with appropriate permissions
Step 3: Retrieve DLP Events Using Enhanced Graph API
With the enhanced API infrastructure, retrieving DLP events becomes more streamlined:
# Authenticate using service principal
$tenantId = "your-tenant-id"
$clientId = $appRegistration.AppId
$clientSecret = "your-client-secret"
$body = @{
grant_type = "client_credentials"
scope = "https://graph.microsoft.com/.default"
client_id = $clientId
client_secret = $clientSecret
}
$authResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method POST -Body $body
$accessToken = $authResponse.access_token
# Set headers for Graph API calls
$headers = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = "application/json"
}
# Retrieve DLP events with enhanced data
$dlpEventsUri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=classification eq 'dataLossPrevention' and createdDateTime ge $((Get-Date).AddDays(-7).ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))"
$dlpEvents = Invoke-RestMethod -Uri $dlpEventsUri -Headers $headers -Method GET
# Display enhanced DLP event data
foreach ($event in $dlpEvents.value) {
Write-Host "Alert ID: $($event.id)"
Write-Host "Title: $($event.title)"
Write-Host "Severity: $($event.severity)"
Write-Host "Classification: $($event.classification)"
Write-Host "DLP Policy: $($event.additionalData.dlpPolicyName)"
Write-Host "Sensitive Info Types: $($event.additionalData.sensitiveInfoTypes -join ', ')"
Write-Host "---"
}
Step 4: Enrich Defender Alerts with DLP Context
Now implement the correlation logic to enrich Defender alerts with DLP event data:
# Function to correlate DLP events with Defender alerts
function Add-DlpContextToDefenderAlerts {
param(
[string]$AccessToken,
[int]$DaysBack = 7
)
$headers = @{
"Authorization" = "Bearer $AccessToken"
"Content-Type" = "application/json"
}
# Get Defender alerts
$defenderAlertsUri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=createdDateTime ge $((Get-Date).AddDays(-$DaysBack).ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))"
$defenderAlerts = Invoke-RestMethod -Uri $defenderAlertsUri -Headers $headers -Method GET
# Get DLP events
$dlpEventsUri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=classification eq 'dataLossPrevention' and createdDateTime ge $((Get-Date).AddDays(-$DaysBack).ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))"
$dlpEvents = Invoke-RestMethod -Uri $dlpEventsUri -Headers $headers -Method GET
foreach ($defenderAlert in $defenderAlerts.value) {
# Correlation logic based on user, time, and affected resources
$correlatedDlpEvents = $dlpEvents.value | Where-Object {
($_.additionalData.userPrincipalName -eq $defenderAlert.additionalData.userPrincipalName) -and
([DateTime]$_.createdDateTime -ge [DateTime]$defenderAlert.createdDateTime.AddMinutes(-30)) -and
([DateTime]$_.createdDateTime -le [DateTime]$defenderAlert.createdDateTime.AddMinutes(30))
}
if ($correlatedDlpEvents.Count -gt 0) {
# Prepare enrichment data
$enrichmentData = @{
dlpEventsCount = $correlatedDlpEvents.Count
dlpPolicies = ($correlatedDlpEvents.additionalData.dlpPolicyName | Select-Object -Unique) -join ", "
sensitiveInfoTypes = ($correlatedDlpEvents.additionalData.sensitiveInfoTypes | Select-Object -Unique) -join ", "
dataClassifications = ($correlatedDlpEvents.additionalData.dataClassifications | Select-Object -Unique) -join ", "
}
# Update Defender alert with DLP context
$updateBody = @{
comments = @(
@{
comment = "Enriched with DLP context: $($enrichmentData.dlpEventsCount) related DLP events found. Policies: $($enrichmentData.dlpPolicies). Sensitive data types: $($enrichmentData.sensitiveInfoTypes)"
createdBy = "DLP-Defender Integration"
createdDateTime = (Get-Date).ToString('yyyy-MM-ddTHH:mm:ss.fffZ')
}
)
customProperties = $enrichmentData
} | ConvertTo-Json -Depth 3
$updateUri = "https://graph.microsoft.com/v1.0/security/alerts_v2/$($defenderAlert.id)"
try {
Invoke-RestMethod -Uri $updateUri -Headers $headers -Method PATCH -Body $updateBody
Write-Host "Successfully enriched alert $($defenderAlert.id) with DLP context" -ForegroundColor Green
}
catch {
Write-Warning "Failed to enrich alert $($defenderAlert.id): $($_.Exception.Message)"
}
}
}
}
# Execute the enrichment process
Add-DlpContextToDefenderAlerts -AccessToken $accessToken -DaysBack 7
Step 5: Automate with Azure Logic Apps Integration
For continuous monitoring, create an Azure Logic App to automate this process:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Get_DLP_Events": {
"type": "Http",
"inputs": {
"method": "GET",
"uri": "https://graph.microsoft.com/v1.0/security/alerts_v2?$filter=classification eq 'dataLossPrevention' and createdDateTime ge @{addMinutes(utcNow(), -60)}",
"headers": {
"Authorization": "Bearer @{body('Get_Access_Token')['access_token']}"
}
}
},
"Get_Defender_Alerts": {
"type": "Http",
"inputs": {
"method": "GET",
"uri": "https://graph.microsoft.com/v1.0/security/alerts_v2?$filter=createdDateTime ge @{addMinutes(utcNow(), -60)}",
"headers": {
"Authorization": "Bearer @{body('Get_Access_Token')['access_token']}"
}
}
},
"Correlate_and_Enrich": {
"type": "Foreach",
"foreach": "@body('Get_Defender_Alerts')['value']",
"actions": {
"Update_Alert_with_DLP_Context": {
"type": "Http",
"inputs": {
"method": "PATCH",
"uri": "https://graph.microsoft.com/v1.0/security/alerts_v2/@{items('Correlate_and_Enrich')['id']}",
"headers": {
"Authorization": "Bearer @{body('Get_Access_Token')['access_token']}",
"Content-Type": "application/json"
},
"body": {
"customProperties": {
"dlpCorrelationProcessed": true,
"dlpEventsFound": "@{length(variables('CorrelatedDlpEvents'))}"
}
}
}
}
}
}
},
"triggers": {
"Recurrence": {
"type": "Recurrence",
"recurrence": {
"frequency": "Hour",
"interval": 1
}
}
}
}
}
Verification and Results
After implementing the enhanced Graph API integration, you should observe the following improvements:
Verify DLP Event Data Export
# Verification script to confirm enhanced data availability
$verificationUri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=classification eq 'dataLossPrevention'&`$select=id,title,classification,additionalData&`$top=5"
$verificationResult = Invoke-RestMethod -Uri $verificationUri -Headers $headers -Method GET
foreach ($event in $verificationResult.value) {
Write-Host "Verifying enhanced DLP data for event: $($event.id)"
Write-Host "Additional Data Keys: $($event.additionalData.PSObject.Properties.Name -join ', ')"
# Check for enhanced properties
$enhancedProperties = @('dlpPolicyName', 'sensitiveInfoTypes', 'dataClassifications', 'userPrincipalName')
$missingProperties = $enhancedProperties | Where-Object { $_ -notin $event.additionalData.PSObject.Properties.Name }
if ($missingProperties.Count -eq 0) {
Write-Host "โ
All enhanced properties present" -ForegroundColor Green
} else {
Write-Host "โ Missing properties: $($missingProperties -join ', ')" -ForegroundColor Red
}
}
Monitor Enriched Defender Alerts
Check that Defender alerts are being enriched with DLP context:
# Query enriched alerts
$enrichedAlertsUri = "https://graph.microsoft.com/v1.0/security/alerts_v2?`$filter=customProperties/any(cp: cp/name eq 'dlpEventsCount')"
$enrichedAlerts = Invoke-RestMethod -Uri $enrichedAlertsUri -Headers $headers -Method GET
Write-Host "Found $($enrichedAlerts.value.Count) alerts enriched with DLP context"
foreach ($alert in $enrichedAlerts.value) {
Write-Host "Alert: $($alert.title)"
Write-Host "DLP Events: $($alert.customProperties.dlpEventsCount)"
Write-Host "DLP Policies: $($alert.customProperties.dlpPolicies)"
Write-Host "---"
}
Key Takeaways
- Enhanced API Infrastructure: The new Graph API endpoints provide comprehensive DLP event data with additional context fields for better integration
- Improved Security Visibility: Correlating DLP events with Defender alerts creates a more complete security picture and enables faster incident response
- Automated Enrichment: PowerShell scripts and Logic Apps can automate the correlation process, reducing manual effort for security teams
- Standardized Data Export: The enhanced API provides consistent data formats that integrate seamlessly with existing security workflows
- Real-time Context: Security analysts now have immediate access to data protection context when investigating security incidents
- Scalable Implementation: The solution can be implemented across large environments with proper automation and monitoring
- Compliance Integration: This enhancement bridges the gap between compliance and security operations, supporting both regulatory requirements and threat detection
This enhancement represents a significant step forward in Microsoft's unified security strategy, providing organizations with the tools needed to create comprehensive, context-aware security operations. By implementing these capabilities, security teams can achieve better threat detection, faster incident response, and more effective data protection across their Microsoft 365 environment.