diff --git a/src/powershell/tests/Test-Assessment.35039.md b/src/powershell/tests/Test-Assessment.35039.md new file mode 100644 index 000000000..0e1f2b9cd --- /dev/null +++ b/src/powershell/tests/Test-Assessment.35039.md @@ -0,0 +1,36 @@ +Communication Compliance policies with Copilot content detection enable organizations to monitor and investigate how users interact with Microsoft Copilot in Teams, Outlook, and Microsoft 365 apps. Without Communication Compliance policies configured to capture Copilot interactions, organizations cannot detect when sensitive data is being exposed to AI services, how users are leveraging Copilot with confidential information, or detect potential policy violations involving AI-assisted data processing. + +Copilot interaction capture through Communication Compliance enables organizations to implement governance and oversight of AI usage while maintaining user communication privacy controls. Users may unknowingly expose sensitive data (customer records, financial information, source code, trade secrets) to Copilot, creating a data spillage risk that becomes invisible without activity monitoring. Organizations must enable Communication Compliance policies targeting Copilot interactions to maintain visibility into how AI features are being used with sensitive data and ensure compliance with data governance policies. + +**Remediation action** + +To create and enable Communication Compliance policies for Copilot interaction capture: + +Sign in as a Global Administrator or Compliance Administrator to the Microsoft Purview portal +Navigate to Communication Compliance > Policies +Select "+ Create policy" to start the policy creation workflow +Choose the "Monitor for sensitive content" template or create a custom policy +Name the policy (e.g., "Copilot Data Protection") +Configure the scope (all users or specific groups) +On the Conditions page, add conditions to detect: +Sensitive information types (credit cards, SSN, financial data) +Keywords related to confidential data +Custom patterns for your organization's sensitive data +On the Review settings page, configure: +Reviewers (compliance team members) +Alert volume preference +Review mailbox for alerts +Enable the policy +Verify rule creation via PowerShell using Query 1 and 2 +Via PowerShell (creation requires portal, but verification via cmdlets): + +Connect-ExchangeOnline +Get-SupervisoryReviewRule -IncludeDetails | Select-Object Name, Policy +Get-SupervisoryReviewPolicyV2 | Select-Object Name, Enabled, ReviewMailbox +For more information: + +Create Communication Compliance policies +Communication Compliance message classes +SupervisoryReview cmdlet reference + +%TestResult% diff --git a/src/powershell/tests/Test-Assessment.35039.ps1 b/src/powershell/tests/Test-Assessment.35039.ps1 new file mode 100644 index 000000000..d7737546f --- /dev/null +++ b/src/powershell/tests/Test-Assessment.35039.ps1 @@ -0,0 +1,246 @@ +<# +.SYNOPSIS + Validates that Communication Compliance rules are configured to detect and monitor Copilot content. + +.DESCRIPTION + This test verifies that Communication Compliance rules targeting Copilot interactions are properly + configured and enabled. It checks that supervisory review policies with Copilot-targeting rules + are active and have configured review mailboxes for processing alerts. + +.NOTES + Test ID: 35039 + Category: Communication Compliance + Pillar: Data + Required Module: ExchangeOnlineManagement + Required Connection: Security & Compliance PowerShell +#> + +function Test-Assessment-35039 { + [ZtTest( + Category = 'Communication Compliance', + ImplementationCost = 'Medium', + MinimumLicense = ('Microsoft 365 E5 Compliance'), + Pillar = 'Data', + RiskLevel = 'Medium', + SfiPillar = 'Protect tenants and production systems', + TenantType = ('Workforce'), + TestId = 35039, + Title = 'Communication Compliance Rules Targeting Copilot Content', + UserImpact = 'Medium' + )] + [CmdletBinding()] + param() + + #region Data Collection + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + + $activity = 'Checking Communication Compliance Rules for Copilot Content' + Write-ZtProgress -Activity $activity -Status 'Getting supervisory review rules' + + # Q1: Find Communication Compliance rules targeting Copilot content + $copilotRules = $null + $errorMsg = $null + + try { + $allRules = @(Get-SupervisoryReviewRule -IncludeRuleXml -ErrorAction Stop) + + $copilotRules = @(foreach ($rule in $allRules) { + if (-not [string]::IsNullOrWhiteSpace($rule.RuleXml)) { + try { + # Wrap RuleXml in a root element to handle multiple rule elements + $wrappedXml = "$($rule.RuleXml)" + $ruleXml = [xml]$wrappedXml + $hasCopilotConfig = $false + + # Check for Copilot in multiple possible locations in the XML structure + if ($ruleXml.root) { + $valueElements = $ruleXml.root.GetElementsByTagName('value') + foreach ($valueElement in $valueElements) { + if ($valueElement.'#text' -match 'IPM\.SkypeTeams\.Message\.Copilot') { + $hasCopilotConfig = $true + break + } + } + } + + if ($hasCopilotConfig) { + $rule + } + } + catch { + Write-PSFMessage "Error parsing RuleXml for rule '$($rule.Name)': $_" -Level Warning + } + } + }) + } + catch { + $errorMsg = $_ + Write-PSFMessage "Failed to retrieve supervisory review rules: $_" -Tag Test -Level Warning + } + + # Q2: Resolve Copilot-targeting policies and verify enabled status + $enabledCopilotPolicies = @() + if ($copilotRules -and -not $errorMsg) { + #Write-ZtProgress -Activity $activity -Status 'Verifying policy enabled status' + + try { + $copilotPolicyIdentities = @($copilotRules | Select-Object -ExpandProperty Policy -Unique) + $policies = foreach ($id in $copilotPolicyIdentities.Guid) { + Get-SupervisoryReviewPolicyV2 -Identity $id -ErrorAction SilentlyContinue + } + $enabledCopilotPolicies = @($policies | Where-Object { $_ -and $_.Enabled -eq $true }) + } + catch { + Write-PSFMessage "Failed to retrieve supervisory review policies: $_" -Tag Test -Level Warning + } + } + + # Q3: Verify Copilot capture is active by checking audit logs (optional) + $policyHits = $null + if ($enabledCopilotPolicies) { + Write-ZtProgress -Activity $activity -Status 'Checking audit logs' + + try { + $startDate = (Get-Date).AddDays(-30) + $endDate = Get-Date + $hits = @(Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate -Operations SupervisionRuleMatch -ErrorAction Stop) + + if ($hits) { + $policyNamePattern = ($enabledCopilotPolicies.Name | ForEach-Object { [regex]::Escape($_) }) -join '|' + $policyHits = @($hits | Where-Object { $_.AuditData -match $policyNamePattern -and ($_.AuditData -match $copilotItemClassRegex -or $_.AuditData -match 'Copilot') }) + } + } + catch { + Write-PSFMessage "Failed to check audit logs: $_" -Tag Test -Level Warning + } + } + #endregion Data Collection + + #region Assessment Logic + $passed = $false + $customStatus = $null + + if ($errorMsg) { + # Investigate: Cannot query supervisory review rules (Query 1 failed) + $passed = $false + $customStatus = 'Investigate' + } + elseif ($copilotRules.Count -eq 0) { + # Fail: Query 1 returns no rules matching the Copilot item class regex + $passed = $false + } + elseif ($enabledCopilotPolicies.Count -eq 0) { + # Fail: Query 2 returns no enabled policies + $passed = $false + } + else { + # Verify all enabled policies have ReviewMailbox configured (Query 2 requirement) + $hasValidPolicies = @($enabledCopilotPolicies | Where-Object { $_.ReviewMailbox }).Count -gt 0 + + if ($hasValidPolicies) { + # Pass: Query 1 returns at least 1 rule AND Query 2 returns at least 1 enabled policy with ReviewMailbox + $passed = $true + } + else { + # Fail: Enabled policies exist but none have ReviewMailbox configured + $passed = $false + } + } + #endregion Assessment Logic + + #region Report Generation + $testResultMarkdown = '' + + if ($customStatus -eq 'Investigate') { + $testResultMarkdown = "### Investigate`n`n" + $testResultMarkdown += "Unable to determine Communication Compliance configuration status due to permissions issues or service connection failure." + } + elseif ($passed) { + $testResultMarkdown = "✅ **Status: Pass**`n`n" + $testResultMarkdown += "Communication Compliance rules targeting Copilot content are properly configured and enabled.`n`n" + } + else { + $testResultMarkdown = "❌ **Status: Fail**`n`n" + $testResultMarkdown += "Communication Compliance rules targeting Copilot content are not properly configured or enabled.`n`n" + } + + # Copilot-Targeting Rules section + if ($copilotRules -and $copilotRules.Count -gt 0) { + $testResultMarkdown += "## Copilot-Targeting Rules`n`n" + $testResultMarkdown += "| Rule Name | Associated Policy |`n" + $testResultMarkdown += "| :--- | :--- |`n" + + foreach ($rule in $copilotRules | Sort-Object Name) { + $safeRuleName = Get-SafeMarkdown $rule.Name + $safePolicyName = Get-SafeMarkdown $rule.Policy + + $testResultMarkdown += "| $safeRuleName | $safePolicyName |`n" + } + $testResultMarkdown += "`n" + } + else { + $testResultMarkdown += "## Copilot-Targeting Rules`n`n" + $testResultMarkdown += "No Copilot-targeting rules found.`n`n" + } + + # Enabled Policies section + if ($enabledCopilotPolicies -and $enabledCopilotPolicies.Count -gt 0) { + $testResultMarkdown += "## Enabled Policies`n`n" + $testResultMarkdown += "| Policy Name | Enabled | Review Mailbox |`n" + $testResultMarkdown += "| :--- | :--- | :--- |`n" + + foreach ($policy in $enabledCopilotPolicies | Sort-Object Name) { + $safePolicyName = Get-SafeMarkdown $policy.Name + $reviewMailbox = if ($policy.ReviewMailbox) { Get-SafeMarkdown $policy.ReviewMailbox } else { 'Not configured' } + $enabledStatus = if ($policy.Enabled -eq $true) { 'True' } else { 'False' } + + $testResultMarkdown += "| $safePolicyName | $enabledStatus | $reviewMailbox |`n" + } + $testResultMarkdown += "`n" + } + else { + $testResultMarkdown += "## Enabled Policies`n`n" + $testResultMarkdown += "No enabled policies with Copilot rules found.`n`n" + } + + # Activity Evidence section (Optional) + $testResultMarkdown += "## Activity Evidence (Optional)`n`n" + if ($policyHits -and $policyHits.Count -gt 0) { + $testResultMarkdown += "**Recent Copilot Matches (30 days):** $($policyHits.Count)`n`n" + } + elseif ($enabledCopilotPolicies -and $enabledCopilotPolicies.Count -gt 0) { + $testResultMarkdown += "**Recent Copilot Matches (30 days):** 0`n`n" + } + else { + $testResultMarkdown += "**Recent Copilot Matches (30 days):** No policies configured for audit review.`n`n" + } + + # Summary section + # Summary section + $testResultMarkdown += "## Summary`n`n" + $testResultMarkdown += "* **Total Copilot Rules Found:** $($copilotRules.Count)`n" + $testResultMarkdown += "* **Enabled Policies with Copilot Rules:** $($enabledCopilotPolicies.Count)`n" + + if ($customStatus -eq 'Investigate') { + $testResultMarkdown += "* **Status:** Investigate`n" + } + elseif ($passed) { + $testResultMarkdown += "* **Status:** Pass`n" + } + else { + $testResultMarkdown += "* **Status:** Fail`n" + } + + #endregion Report Generation + + $params = @{ + TestId = '35039' + Title = 'Communication Compliance Rules Targeting Copilot Content' + Status = $passed + Result = $testResultMarkdown + } + if ($customStatus) { + $params.CustomStatus = $customStatus + } + Add-ZtTestResultDetail @params +}