Home
/
Insights
/

How to Audit Microsoft Copilot Activity: Complete Guide to Purview Integration

Back to Insights
Governance & Compliance

How to Audit Microsoft Copilot Activity: Complete Guide to Purview Integration

Microsoft 365 Copilot operates without human oversight—users ask questions, AI retrieves documents, responses are generated, and nobody knows what just happe...

Copilot Consulting

August 23, 2025

17 min read

Hero image for How to Audit Microsoft Copilot Activity: Complete Guide to Purview Integration
Illustration 1 for How to Audit Microsoft Copilot Activity: Complete Guide to Purview Integration

Microsoft 365 Copilot operates without human oversight—users ask questions, AI retrieves documents, responses are generated, and nobody knows what just happened unless you've configured audit logging. This creates a compliance gap that most organizations discover during breach investigations or regulatory audits: you can't answer basic questions like "Who accessed confidential M&A documents through Copilot last month?" or "Which employees queried customer financial data?"

Microsoft Purview Audit captures Copilot interactions, but only if you've enabled the right settings, configured adequate retention periods, and implemented monitoring infrastructure. Standard Audit (free with Microsoft 365) provides 90-day retention—inadequate for HIPAA (6 years), SOX (7 years), or GDPR (varies by member state). Premium Audit extends to 1 year for user activities and 10 years for specific events, but requires additional licensing.

This guide provides the technical framework for comprehensive Copilot audit logging: what events are captured, how to query logs, retention policy configuration, and SIEM integration for real-time alerting.

Microsoft Purview Audit Architecture

Microsoft Purview Audit operates as the unified audit log platform for Microsoft 365 services. All Copilot interactions flow through the Unified Audit Log (UAL), where they're stored as structured events with metadata.

Audit Log Tiers: Standard vs. Premium

| Feature | Standard Audit (Free) | Premium Audit (E5/A5/G5) | |---------|----------------------|--------------------------| | Retention period | 90 days | 1 year (user), 10 years (admin/mailbox) | | Copilot event capture | Yes | Yes | | High-value event identification | No | Yes | | Custom retention policies | No | Yes | | API access for export | Limited (90 days) | Full (retention period) | | Bandwidth throttling | 2,000 requests/minute | 10,000 requests/minute | | Required licensing | Microsoft 365 E3/A3/G3+ | Microsoft 365 E5/A5/G5 or add-on |

Critical: Standard Audit's 90-day retention is insufficient for most compliance frameworks. HIPAA requires 6 years, SOX requires 7 years, and SEC Rule 17a-4 requires 7 years. Premium Audit is not optional for regulated industries—it's a compliance requirement.

Copilot Audit Event Types

Microsoft Purview captures multiple event types for Copilot interactions:

| Event Type | RecordType | Description | Captured Data | |-----------|------------|-------------|---------------| | CopilotInteraction | 65 | User query submitted to Copilot | Query text, timestamp, user identity | | CopilotDocumentRetrieval | 66 | Document accessed by Copilot for response generation | Document URL, sensitivity label, permissions | | CopilotResponseGenerated | 67 | AI response delivered to user | Response summary, source documents, confidence score | | CopilotDataExport | 68 | User exports Copilot response data | Export format, destination, data volume | | CopilotPluginInvocation | 69 | Copilot invokes external plugin (Graph Connectors, third-party apps) | Plugin name, API calls, data accessed |

Important: RecordType values may change as Microsoft updates Copilot audit schema. Always verify current event types using Get-UnifiedAuditLogRecordType cmdlet.

What's Captured in Copilot Audit Logs

Each Copilot audit event contains structured JSON with key fields:

{
  "CreationTime": "2025-08-23T14:32:18Z",
  "UserId": "jsmith@contoso.com",
  "Operation": "CopilotInteraction",
  "RecordType": 65,
  "Workload": "MicrosoftCopilot",
  "ClientIP": "203.0.113.45",
  "UserAgent": "Microsoft Copilot Web Client/1.0",
  "AuditData": {
    "QueryText": "Show me Q3 financial projections for Europe",
    "QueryLanguage": "en-US",
    "DocumentsAccessed": [
      {
        "DocumentId": "12345678-1234-1234-1234-123456789012",
        "DocumentUrl": "https://contoso.sharepoint.com/sites/Finance/Q3-Projections.xlsx",
        "SensitivityLabel": "Confidential - Finance Only",
        "AccessMethod": "SemanticSearch"
      }
    ],
    "ResponseSummary": "Retrieved financial projections showing 15% growth in European markets",
    "PluginsInvoked": [],
    "DataClassifications": ["Financial Data", "Confidential"]
  }
}

Key fields for compliance analysis:

  • UserId: Who accessed data through Copilot
  • QueryText: What the user asked (critical for intent analysis)
  • DocumentsAccessed: Which documents Copilot retrieved (critical for permission audits)
  • SensitivityLabel: Whether Copilot accessed labeled/encrypted content
  • DataClassifications: What type of sensitive data was involved

Learn more about our Copilot Audit Architecture service.

Enabling and Configuring Audit Logging

Step 1: Verify Audit Logging is Enabled

Most Microsoft 365 tenants have audit logging enabled by default, but verify before Copilot deployment.

# Connect to Exchange Online PowerShell
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

# Check organization-wide audit status
Get-OrganizationConfig | Select-Object AuditDisabled

# If AuditDisabled = True, enable audit logging
Set-OrganizationConfig -AuditDisabled $false

# Enable mailbox auditing for all users (required for full coverage)
Get-Mailbox -ResultSize Unlimited | Set-Mailbox -AuditEnabled $true -AuditOwner MailboxLogin,HardDelete,SoftDelete,Update,Move

Verification: After enabling, wait 24 hours for audit infrastructure to fully activate.

Step 2: Enable Premium Audit Features

Premium Audit requires Microsoft 365 E5/A5/G5 licensing or Compliance add-on.

# Verify Premium Audit licensing
Get-MsolAccountSku | Where-Object { $_.AccountSkuId -like "*E5*" -or $_.AccountSkuId -like "*COMPLIANCE*" }

# Enable high-value events for Premium Audit
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true

# Configure verbose logging (captures full query text and document metadata)
Set-AdminAuditLogConfig -LogLevel Verbose

# Enable search and export throttling increase
Set-AdminAuditLogConfig -ThrottlingEnabled $false

Step 3: Configure Custom Retention Policies

Premium Audit allows custom retention policies per event type and user group.

# Create 6-year retention policy for Copilot events (HIPAA compliance)
New-UnifiedAuditLogRetentionPolicy -Name "Copilot Audit - 6 Year Retention" `
    -Description "Retains Copilot interaction logs for HIPAA compliance" `
    -RecordTypes CopilotInteraction,CopilotDocumentRetrieval,CopilotResponseGenerated `
    -RetentionDuration TenYears `
    -Priority 100

# Create 7-year retention policy for financial data access (SOX compliance)
New-UnifiedAuditLogRetentionPolicy -Name "Copilot Audit - Financial Data - 7 Years" `
    -Description "Retains Copilot access to financial data for SOX compliance" `
    -RecordTypes CopilotInteraction,CopilotDocumentRetrieval `
    -Operations "CopilotInteraction" `
    -UserIds "Finance-Team@contoso.com" `
    -RetentionDuration TenYears `
    -Priority 200

# Create 1-year retention policy for general users (default)
New-UnifiedAuditLogRetentionPolicy -Name "Copilot Audit - General Users - 1 Year" `
    -Description "Retains Copilot audit logs for all other users" `
    -RecordTypes CopilotInteraction,CopilotDocumentRetrieval,CopilotResponseGenerated `
    -RetentionDuration TwelveMonths `
    -Priority 50

Important: Retention policies with higher Priority values take precedence. Configure specific policies (e.g., finance team) with higher priority than general policies.

Step 4: Verify Audit Pipeline is Operational

# Test audit pipeline by searching for recent admin activities
Search-UnifiedAuditLog -StartDate (Get-Date).AddHours(-24) -EndDate (Get-Date) `
    -RecordType AzureActiveDirectory `
    -ResultSize 100 |
Select-Object CreationDate, UserIds, Operations, RecordType

# Verify Copilot events are being captured (requires active Copilot usage)
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
    -RecordType CopilotInteraction `
    -ResultSize 100 |
Select-Object CreationDate, UserIds, Operations, AuditData

# If no results, verify:
# 1. Audit logging is enabled (Step 1)
# 2. Users have Copilot licenses
# 3. Users have actually used Copilot in the past 7 days
# 4. Wait 24-48 hours after enabling audit logging

Querying Copilot Audit Logs

Basic Search Queries

Microsoft provides Search-UnifiedAuditLog cmdlet for querying audit data.

# Query all Copilot interactions in the last 30 days
$startDate = (Get-Date).AddDays(-30)
$endDate = Get-Date

$copilotLogs = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -ResultSize 5000

# Export to CSV for analysis
$copilotLogs | Select-Object CreationDate, UserIds, Operations, AuditData |
Export-Csv -Path "C:\Audit\CopilotActivity-30Days.csv" -NoTypeInformation

Important: Search-UnifiedAuditLog returns maximum 5,000 results per query. For large result sets, use pagination with -SessionId and -SessionCommand.

Paginated Search for Large Result Sets

# Search with pagination for result sets > 5,000 entries
$startDate = (Get-Date).AddDays(-90)
$endDate = Get-Date
$sessionId = "CopilotAudit-" + (Get-Date -Format "yyyyMMdd-HHmmss")
$results = @()

# Initial search
$initialResults = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -SessionId $sessionId `
    -SessionCommand ReturnLargeSet `
    -ResultSize 5000

$results += $initialResults

# Continue pagination until no more results
$resultCount = ($initialResults | Measure-Object).Count
$pageIndex = 1

while ($resultCount -ge 5000) {
    $pageResults = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
        -RecordType CopilotInteraction `
        -SessionId $sessionId `
        -SessionCommand ReturnNextPreviewPage `
        -ResultSize 5000

    $results += $pageResults
    $resultCount = ($pageResults | Measure-Object).Count
    $pageIndex++

    Write-Progress -Activity "Fetching Copilot Audit Logs" -Status "Page $pageIndex" -PercentComplete (($results.Count / 50000) * 100)
}

Write-Output "Retrieved $($results.Count) total audit entries"
$results | Export-Csv -Path "C:\Audit\CopilotActivity-Full.csv" -NoTypeInformation

Advanced Queries: Filtering by User, Document, and Sensitivity Label

# Find all Copilot queries by specific user
$targetUser = "jsmith@contoso.com"

$userLogs = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
    -RecordType CopilotInteraction `
    -UserIds $targetUser `
    -ResultSize 5000

$userLogs | ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
        Timestamp = $_.CreationDate
        User = $_.UserIds
        Query = $auditData.QueryText
        DocumentsAccessed = ($auditData.DocumentsAccessed | Measure-Object).Count
        SensitiveDataTypes = ($auditData.DataClassifications -join ", ")
    }
} | Export-Csv -Path "C:\Audit\UserActivity-$targetUser.csv" -NoTypeInformation
# Find all Copilot access to documents with specific sensitivity label
$targetLabel = "Confidential - M&A"

$allLogs = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) `
    -RecordType CopilotInteraction `
    -ResultSize 5000

$labeledAccess = $allLogs | ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $matchedDocs = $auditData.DocumentsAccessed | Where-Object { $_.SensitivityLabel -eq $targetLabel }

    if ($matchedDocs) {
        [PSCustomObject]@{
            Timestamp = $_.CreationDate
            User = $_.UserIds
            Query = $auditData.QueryText
            DocumentUrl = ($matchedDocs.DocumentUrl -join "; ")
            SensitivityLabel = $targetLabel
        }
    }
}

$labeledAccess | Export-Csv -Path "C:\Audit\ConfidentialAccess-$targetLabel.csv" -NoTypeInformation
# Find high-risk queries (accessing multiple confidential documents)
$riskThreshold = 10  # Alert if user accessed 10+ confidential docs in single query

$highRiskQueries = $allLogs | ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $confidentialDocs = $auditData.DocumentsAccessed | Where-Object { $_.SensitivityLabel -like "Confidential*" }
    $docCount = ($confidentialDocs | Measure-Object).Count

    if ($docCount -ge $riskThreshold) {
        [PSCustomObject]@{
            Timestamp = $_.CreationDate
            User = $_.UserIds
            Query = $auditData.QueryText
            ConfidentialDocsAccessed = $docCount
            DocumentUrls = ($confidentialDocs.DocumentUrl -join "; ")
            RiskLevel = if ($docCount -ge 50) { "Critical" } elseif ($docCount -ge 20) { "High" } else { "Medium" }
        }
    }
}

$highRiskQueries | Sort-Object ConfidentialDocsAccessed -Descending |
Export-Csv -Path "C:\Audit\HighRiskQueries.csv" -NoTypeInformation

Automated Daily Audit Report

# Daily audit report script (schedule with Task Scheduler)
$reportDate = Get-Date
$startDate = $reportDate.AddDays(-1)
$endDate = $reportDate

$dailyLogs = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -ResultSize 5000

# Generate summary statistics
$summary = @{
    Date = $reportDate.ToString("yyyy-MM-dd")
    TotalQueries = ($dailyLogs | Measure-Object).Count
    UniqueUsers = ($dailyLogs | Select-Object -ExpandProperty UserIds -Unique | Measure-Object).Count
    ConfidentialAccess = 0
    HighRiskQueries = 0
}

$detailedLogs = $dailyLogs | ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $confidentialDocs = $auditData.DocumentsAccessed | Where-Object { $_.SensitivityLabel -like "Confidential*" }

    if ($confidentialDocs) {
        $summary.ConfidentialAccess++

        if (($confidentialDocs | Measure-Object).Count -ge 10) {
            $summary.HighRiskQueries++
        }
    }

    [PSCustomObject]@{
        Timestamp = $_.CreationDate
        User = $_.UserIds
        Query = $auditData.QueryText
        DocumentsAccessed = ($auditData.DocumentsAccessed | Measure-Object).Count
        ConfidentialDocuments = ($confidentialDocs | Measure-Object).Count
        DataClassifications = ($auditData.DataClassifications -join ", ")
    }
}

# Export summary
$summary | ConvertTo-Json | Out-File "C:\Audit\Reports\Summary-$($reportDate.ToString('yyyyMMdd')).json"

# Export detailed logs
$detailedLogs | Export-Csv -Path "C:\Audit\Reports\Details-$($reportDate.ToString('yyyyMMdd')).csv" -NoTypeInformation

# Send email report to security team
Send-MailMessage -From "audit@contoso.com" -To "security-team@contoso.com" `
    -Subject "Daily Copilot Audit Report - $($reportDate.ToString('yyyy-MM-dd'))" `
    -Body "Total Queries: $($summary.TotalQueries)`nUnique Users: $($summary.UniqueUsers)`nConfidential Access: $($summary.ConfidentialAccess)`nHigh-Risk Queries: $($summary.HighRiskQueries)" `
    -Attachments "C:\Audit\Reports\Details-$($reportDate.ToString('yyyyMMdd')).csv" `
    -SmtpServer "smtp.contoso.com"

Learn more about our Audit Reporting Automation service.

SIEM Integration for Real-Time Monitoring

Exporting audit logs to a Security Information and Event Management (SIEM) platform enables real-time alerting, correlation with other security events, and long-term retention beyond Purview's limits.

Azure Sentinel Integration

Azure Sentinel (Microsoft's cloud-native SIEM) provides native integration with Microsoft 365 Audit Logs.

Step 1: Enable Azure Sentinel Data Connector

  1. Navigate to Azure Sentinel workspace
  2. Go to "Data connectors"
  3. Select "Microsoft 365 (Preview)"
  4. Click "Open connector page"
  5. Enable "Exchange", "SharePoint", "Teams", and "Copilot" logs
  6. Configure log retention (90 days to 2 years based on tier)

Step 2: Create Analytics Rules for Copilot Events

// Azure Sentinel KQL query: Detect mass confidential document access via Copilot
OfficeActivity
| where RecordType == "CopilotInteraction"
| extend AuditDetails = parse_json(AuditData)
| extend QueryText = tostring(AuditDetails.QueryText)
| extend DocumentsAccessed = parse_json(AuditDetails.DocumentsAccessed)
| mv-expand DocumentsAccessed
| extend SensitivityLabel = tostring(DocumentsAccessed.SensitivityLabel)
| where SensitivityLabel contains "Confidential"
| summarize ConfidentialDocsAccessed = count(), QueryList = make_set(QueryText) by UserId, bin(TimeGenerated, 1h)
| where ConfidentialDocsAccessed >= 20
| project TimeGenerated, UserId, ConfidentialDocsAccessed, QueryList

Step 3: Configure Automated Response

// Create alert rule that triggers incident and disables Copilot access
// Configure in Azure Sentinel Analytics > Create > Scheduled query rule
// Alert threshold: ConfidentialDocsAccessed >= 20
// Frequency: Every 15 minutes
// Actions: Create incident, run playbook "Disable-CopilotAccess"

Playbook for automated response (Azure Logic App):

{
  "definition": {
    "actions": {
      "Disable_Copilot_License": {
        "type": "Http",
        "inputs": {
          "method": "POST",
          "uri": "https://graph.microsoft.com/v1.0/users/@{triggerBody()?['UserId']}/assignLicense",
          "authentication": {
            "type": "ManagedServiceIdentity"
          },
          "body": {
            "addLicenses": [],
            "removeLicenses": ["COPILOT_LICENSE_GUID"]
          }
        }
      },
      "Send_Security_Alert": {
        "type": "Office365.SendEmail",
        "inputs": {
          "to": "security-team@contoso.com",
          "subject": "Copilot Access Disabled - Suspicious Activity",
          "body": "User @{triggerBody()?['UserId']} accessed @{triggerBody()?['ConfidentialDocsAccessed']} confidential documents via Copilot. Access disabled pending investigation."
        }
      }
    }
  }
}

Splunk Integration

For organizations using Splunk, integrate via HTTP Event Collector (HEC).

Step 1: Configure Splunk HEC Endpoint

  1. Splunk > Settings > Data Inputs > HTTP Event Collector
  2. Create new token: "Microsoft 365 Audit Logs"
  3. Note HEC URL and token

Step 2: Export Audit Logs to Splunk

# PowerShell script to export Copilot logs to Splunk HEC
$splunkHec = "https://splunk.contoso.com:8088/services/collector"
$splunkToken = "12345678-1234-1234-1234-123456789012"

$copilotLogs = Search-UnifiedAuditLog -StartDate (Get-Date).AddHours(-1) -EndDate (Get-Date) `
    -RecordType CopilotInteraction `
    -ResultSize 5000

foreach ($log in $copilotLogs) {
    $auditData = $log.AuditData | ConvertFrom-Json

    $splunkEvent = @{
        time = (Get-Date $log.CreationDate -UFormat %s)
        sourcetype = "microsoft:365:audit:copilot"
        event = @{
            timestamp = $log.CreationDate
            user = $log.UserIds
            operation = $log.Operations
            query = $auditData.QueryText
            documents_accessed = ($auditData.DocumentsAccessed | Measure-Object).Count
            data_classifications = ($auditData.DataClassifications -join ", ")
        }
    } | ConvertTo-Json -Compress

    Invoke-RestMethod -Method Post -Uri $splunkHec `
        -Headers @{ "Authorization" = "Splunk $splunkToken" } `
        -Body $splunkEvent `
        -ContentType "application/json"
}

Step 3: Create Splunk Alert

index=microsoft365 sourcetype="microsoft:365:audit:copilot"
| eval confidential_docs=mvcount(documents_accessed{@SensitivityLabel="Confidential*"})
| where confidential_docs >= 20
| stats count as alert_count by user, confidential_docs
| where alert_count >= 1
| eval severity="high"
| table _time, user, confidential_docs, query, alert_count, severity

Configure alert action: Email security team, create ticket in ServiceNow, disable user's Copilot license.

Learn more about our SIEM Integration service.

Compliance Use Cases for Audit Logs

Use Case 1: HIPAA § 164.312(b) Audit Controls

Requirement: Record and examine access to ePHI.

Implementation:

# Monthly HIPAA audit report: All Copilot access to PHI documents
$startDate = (Get-Date).AddMonths(-1)
$endDate = Get-Date

$phiAccess = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -ResultSize 5000 |
ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $phiDocs = $auditData.DocumentsAccessed | Where-Object { $_.SensitivityLabel -like "*PHI*" }

    if ($phiDocs) {
        [PSCustomObject]@{
            Timestamp = $_.CreationDate
            User = $_.UserIds
            Role = (Get-AzureADUser -ObjectId $_.UserIds).JobTitle
            Query = $auditData.QueryText
            PHIDocumentsAccessed = ($phiDocs | Measure-Object).Count
            DocumentUrls = ($phiDocs.DocumentUrl -join "; ")
            AuthorizedAccess = if ((Get-AzureADUserMembership -ObjectId $_.UserIds).DisplayName -contains "PHI-Authorized-Users") { "Yes" } else { "No" }
        }
    }
}

$phiAccess | Export-Csv -Path "C:\Compliance\HIPAA-Audit-Report-$(Get-Date -Format 'yyyyMM').csv" -NoTypeInformation

# Identify unauthorized access
$unauthorizedAccess = $phiAccess | Where-Object { $_.AuthorizedAccess -eq "No" }

if ($unauthorizedAccess) {
    # Trigger breach investigation workflow
    Send-MailMessage -From "compliance@hospital.com" -To "privacy-officer@hospital.com" `
        -Subject "URGENT: Unauthorized PHI Access Detected via Copilot" `
        -Body "Unauthorized access detected. Review attached report immediately." `
        -Attachments "C:\Compliance\HIPAA-Audit-Report-$(Get-Date -Format 'yyyyMM').csv"
}

Use Case 2: SOX Section 404 IT General Controls

Requirement: Maintain audit trails for access to financial reporting systems.

Implementation:

# Quarterly SOX audit: Copilot access to financial data by non-Finance users
$quarter = "Q3-2025"
$startDate = Get-Date "2025-07-01"
$endDate = Get-Date "2025-09-30"

$financialAccess = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -ResultSize 5000 |
ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $financialDocs = $auditData.DocumentsAccessed | Where-Object { $_.DocumentUrl -like "*/sites/Finance/*" }

    if ($financialDocs) {
        $user = Get-AzureADUser -ObjectId $_.UserIds
        $isFinanceTeam = (Get-AzureADUserMembership -ObjectId $_.UserIds).DisplayName -contains "Finance-Team"

        [PSCustomObject]@{
            Timestamp = $_.CreationDate
            User = $_.UserIds
            Department = $user.Department
            IsAuthorized = $isFinanceTeam
            Query = $auditData.QueryText
            FinancialDocumentsAccessed = ($financialDocs | Measure-Object).Count
            DocumentUrls = ($financialDocs.DocumentUrl -join "; ")
        }
    }
}

# Export for external auditors
$financialAccess | Export-Csv -Path "C:\Compliance\SOX-Audit-$quarter.csv" -NoTypeInformation

# Generate exception report (non-Finance users accessing financial data)
$exceptions = $financialAccess | Where-Object { -not $_.IsAuthorized }
$exceptions | Export-Csv -Path "C:\Compliance\SOX-Exceptions-$quarter.csv" -NoTypeInformation

Use Case 3: GDPR Article 30 Records of Processing Activities

Requirement: Document processing activities including who accessed personal data.

Implementation:

# GDPR Article 30 record: All Copilot processing of personal data
$startDate = (Get-Date).AddYears(-1)
$endDate = Get-Date

$personalDataProcessing = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate `
    -RecordType CopilotInteraction `
    -ResultSize 5000 |
ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    $personalDataDocs = $auditData.DocumentsAccessed | Where-Object {
        $_.DataClassifications -contains "EU Personal Data" -or
        $_.SensitivityLabel -like "*Personal*"
    }

    if ($personalDataDocs) {
        [PSCustomObject]@{
            Timestamp = $_.CreationDate
            User = $_.UserIds
            ProcessingPurpose = $auditData.QueryText
            DataCategories = ($auditData.DataClassifications -join ", ")
            DataSubjects = "Customers, Employees"  # Infer from document context
            LegalBasis = "Legitimate Interest - Article 6(1)(f)"
            Recipients = "Internal employees only"
            RetentionPeriod = "1 year"
        }
    }
}

$personalDataProcessing | Export-Csv -Path "C:\Compliance\GDPR-Article30-Record.csv" -NoTypeInformation

Learn more about our Compliance Reporting Framework service.

Performance Optimization and Troubleshooting

Issue 1: Search-UnifiedAuditLog Timeouts

Symptom: Queries timeout after 5 minutes with no results.

Root cause: Large result sets, insufficient bandwidth, or throttling.

Solution:

# Implement retry logic with exponential backoff
function Search-AuditLogWithRetry {
    param(
        [DateTime]$StartDate,
        [DateTime]$EndDate,
        [string]$RecordType,
        [int]$MaxRetries = 5
    )

    $retryCount = 0
    $backoffSeconds = 2

    while ($retryCount -lt $MaxRetries) {
        try {
            $results = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate `
                -RecordType $RecordType -ResultSize 5000 -ErrorAction Stop

            return $results
        }
        catch {
            $retryCount++
            Write-Warning "Search failed (attempt $retryCount/$MaxRetries). Retrying in $backoffSeconds seconds..."
            Start-Sleep -Seconds $backoffSeconds
            $backoffSeconds *= 2  # Exponential backoff
        }
    }

    throw "Audit log search failed after $MaxRetries attempts"
}

# Use function
$logs = Search-AuditLogWithRetry -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) -RecordType "CopilotInteraction"

Issue 2: Missing Copilot Events in Audit Log

Symptom: Search-UnifiedAuditLog returns no Copilot events despite active usage.

Troubleshooting checklist:

  1. Verify audit logging is enabled: Get-OrganizationConfig | Select-Object AuditDisabled
  2. Check user has Copilot license: Get-MgUserLicenseDetail -UserId user@contoso.com
  3. Wait for audit pipeline delay: Up to 24 hours for initial events
  4. Verify RecordType value: Use Get-UnifiedAuditLogRecordType to confirm current schema
  5. Check Premium Audit licensing: Standard tier may not capture all event details

Issue 3: Incomplete AuditData Field

Symptom: AuditData JSON is missing expected fields like QueryText or DocumentsAccessed.

Root cause: Standard Audit captures limited metadata. Premium Audit required for full details.

Solution: Upgrade to Microsoft 365 E5 or purchase Compliance add-on.

Frequently Asked Questions

How do I audit Copilot usage in my Microsoft 365 tenant?

Enable Microsoft Purview Audit (included in Microsoft 365 E3+) by running Set-OrganizationConfig -AuditDisabled $false in Exchange Online PowerShell, then enable mailbox auditing for all users with Get-Mailbox -ResultSize Unlimited | Set-Mailbox -AuditEnabled $true. Query Copilot audit events using Search-UnifiedAuditLog -RecordType CopilotInteraction cmdlet. Standard Audit provides 90-day retention; Premium Audit (E5 required) extends to 1 year with custom retention policies up to 10 years. Audit logs capture user identity, query text, documents accessed, sensitivity labels, and data classifications—critical for compliance investigations and breach analysis.

Can I see what users asked Copilot and what documents were retrieved?

Yes, if you have Premium Audit enabled. Standard Audit captures limited metadata; Premium Audit (Microsoft 365 E5/A5/G5 or Compliance add-on) captures full query text in the QueryText field and document details in the DocumentsAccessed array, including document URLs, sensitivity labels, and access methods. Query using PowerShell: Search-UnifiedAuditLog -RecordType CopilotInteraction | ForEach-Object { $_.AuditData | ConvertFrom-Json }. For ongoing monitoring, export to SIEM platform (Azure Sentinel, Splunk) with automated alerting for high-risk queries accessing confidential documents. GDPR requires this level of detail for data subject access requests (Article 15).

How long are Copilot audit logs retained?

Standard Audit (free with Microsoft 365 E3+): 90 days. Premium Audit (Microsoft 365 E5/A5/G5 or add-on): 1 year default, configurable up to 10 years using custom retention policies. For compliance frameworks requiring longer retention (HIPAA 6 years, SOX 7 years, SEC 17a-4 7 years), Premium Audit is mandatory. Configure extended retention using New-UnifiedAuditLogRetentionPolicy cmdlet with RetentionDuration TenYears. Alternatively, export audit logs to external SIEM or data lake for indefinite retention beyond Microsoft's limits. Retention policies apply per RecordType—configure separate policies for Copilot events vs. general Microsoft 365 activities.

How do I integrate Copilot audit logs with my SIEM platform?

For Azure Sentinel: Enable native "Microsoft 365" data connector in Sentinel workspace, which automatically ingests audit logs including Copilot events. For third-party SIEM (Splunk, QRadar, LogRhythm): Export logs via PowerShell script using Search-UnifiedAuditLog cmdlet and HTTP Event Collector (HEC) or syslog forwarding. Schedule script to run every 15-60 minutes to maintain near real-time visibility. Export includes full AuditData JSON with query text, document URLs, and sensitivity labels. Configure SIEM analytics rules to detect anomalous patterns: mass confidential document access, after-hours queries, access by terminated users, or cross-border data transfers. Learn about our SIEM Integration service.

What's the difference between Standard Audit and Premium Audit for Copilot?

Standard Audit (free with E3+): 90-day retention, 2,000 API requests/minute throttle, basic event metadata (timestamp, user, operation). Premium Audit (E5 or add-on): 1-10 year retention, 10,000 requests/minute, full event details (query text, documents accessed, sensitivity labels), custom retention policies per user/group, high-value event identification, and priority support. For Copilot governance, Premium Audit is essential—Standard's 90-day retention is insufficient for regulatory compliance, and limited metadata prevents effective breach investigations. Premium cost: $5/user/month as add-on, or included in Microsoft 365 E5 ($57/user/month). ROI justification: single compliance violation fine exceeds annual Premium Audit cost for most organizations.

Illustration 2 for How to Audit Microsoft Copilot Activity: Complete Guide to Purview Integration
Microsoft Copilot
AI
Governance
Compliance
Data Security

Related Articles

Need Help With Your Copilot Deployment?

Our team of experts can help you navigate the complexities of Microsoft 365 Copilot implementation with a risk-first approach.

Schedule a Consultation