Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/powershell/tests/Test-Assessment.35016.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
When sensitivity labels are not mandatory, users can send unclassified emails, share unclassified files and documents, create unclassified sites and groups, and publish unclassified Power BI content without applying appropriate protection labels. This creates a significant security and compliance risk because threat actors can easily exfiltrate sensitive data without any classification metadata to indicate its sensitivity level or trigger automated protection policies. Mandatory labeling must be configured across all workloads (Outlook for emails, Teams for teamwork, SharePoint/Microsoft 365 Groups for sites and groups, and Power BI for analytics content) to ensure comprehensive coverage. If data loss prevention (DLP) policies rely on label detection to identify and block sensitive content, unclassified data bypasses these controls entirely. Additionally, users may accidentally share confidential information without realizing it lacks proper protection, and organizations lose audit trail visibility into what data is being handled and how. Without mandatory labeling across all platforms, compliance frameworks such as GDPR, HIPAA, or industry-specific regulations cannot be effectively enforced because sensitive data remains unidentified. Organizations should implement at least one sensitivity label policy with mandatory labeling enabled across Outlook, Teams/Teamwork, SharePoint/Sites and Groups, and Power BI to ensure all communications, documents, and analytics content are classified before sharing, enabling both automated protection mechanisms and complete audit visibility.

**Remediation action**
1. Navigate to Sensitivity label policies in Microsoft Purview
- [Sensitivity label policies](https://purview.microsoft.com/informationprotection/labelpolicies)
2. Create or update a policy to enable mandatory labeling for target workloads (Outlook, Teams, SharePoint, Power BI)
3. Enable specific settings:
- "Require users to apply a label to their email" (Outlook)
- "Require users to apply a label for Teams, groups, and SharePoint content" (collaboration)
- Mandatory labeling for Power BI content
4. Set policy scope (global or specific groups)
5. Test with pilot users before organization-wide rollout

**Learn More:** [Require users to apply a label](https://learn.microsoft.com/en-us/purview/sensitivity-labels-office-apps#require-users-to-apply-a-label-to-their-email-and-documents)

<!--- Results --->
%TestResult%
255 changes: 255 additions & 0 deletions src/powershell/tests/Test-Assessment.35016.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
<#
.SYNOPSIS
Mandatory Labeling Enabled for Sensitivity Labels
#>

function Test-Assessment-35016 {
[ZtTest(
Category = 'Information Protection',
ImplementationCost = 'Medium',
MinimumLicense = ('Microsoft 365 E3'),
Pillar = 'Data',
RiskLevel = 'High',
SfiPillar = 'Protect tenants and production systems',
TenantType = ('Workforce','External'),
TestId = 35016,
Title = 'Mandatory labeling enabled for sensitivity labels',
UserImpact = 'High'
)]
[CmdletBinding()]
param()

#region Data Collection
Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose

$activity = 'Checking mandatory labeling configuration'
Write-ZtProgress -Activity $activity -Status 'Getting sensitivity label policies'

$errorMsg = $null
$enabledPolicies = @()

try {
# Q1: Retrieve all enabled sensitivity label policies to assess mandatory labeling configuration
$enabledPolicies = Get-LabelPolicy -ErrorAction Stop | Where-Object { $_.Enabled -eq $true }
}
catch {
$errorMsg = $_
Write-PSFMessage "Error querying label policies: $_" -Level Error
}
#endregion Data Collection

#region Assessment Logic
$allPolicySettings = @()
$mandatoryPolicies = @()
$xmlParseErrors = @()
$passed = $false
$customStatus = $null

if ($errorMsg) {
$testResultMarkdown = "⚠️ Unable to determine mandatory labeling status due to error: $errorMsg`n`n"
$customStatus = 'Investigate'
}
else {
Write-PSFMessage "Found $($enabledPolicies.Count) enabled label policies" -Level Verbose

try {
# Examine label policy settings for mandatory labeling
foreach ($policy in $enabledPolicies) {
# Determine policy scope:
# - Global if any location is set to "All"
# - Scoped if specific users/groups are defined
$allLocationNames = @(
$policy.ExchangeLocation.Name
$policy.ModernGroupLocation.Name
$policy.SharePointLocation.Name
$policy.OneDriveLocation.Name
$policy.SkypeLocation.Name
$policy.PublicFolderLocation.Name
) | Where-Object { $_ }

$isGlobal = $allLocationNames -contains 'All'

$policySettings = @{
PolicyName = $policy.Name
Guid = $policy.Guid
Enabled = $policy.Enabled
EmailMandatory = $false
TeamworkMandatory = $false
SiteGroupMandatory = $false
PowerBIMandatory = $false
EmailOverride = $false
Scope = if ($isGlobal) { 'Global' } else { 'Scoped' }
LabelsCount = $policy.Labels.Count
}

# Parse PolicySettingsBlob XML for mandatory labeling flags
if (-not [string]::IsNullOrWhiteSpace($policy.PolicySettingsBlob)) {
try {
$xmlSettings = [xml]$policy.PolicySettingsBlob

# Validate XML structure before accessing properties
if ($xmlSettings.settings -and $xmlSettings.settings.setting) {
# Access settings as XML elements for direct property lookup
foreach ($setting in $xmlSettings.settings.setting) {
# Add null safety for key and value attributes
if (-not $setting.key -or -not $setting.value) {
Write-PSFMessage "Skipping setting with null key or value in policy '$($policy.Name)'" -Level Verbose
continue
}

$key = $setting.key.ToLower()
$value = $setting.value.ToLower()

switch ($key) {
'mandatory' {
$policySettings.EmailMandatory = ($value -eq 'true')
}
'teamworkmandatory' {
$policySettings.TeamworkMandatory = ($value -eq 'true')
}
'siteandgroupmandatory' {
$policySettings.SiteGroupMandatory = ($value -eq 'true')
}
'powerbimandatory' {
$policySettings.PowerBIMandatory = ($value -eq 'true')
}
'disablemandatoryinoutlook' {
$policySettings.EmailOverride = ($value -eq 'true')
}
default {
Write-PSFMessage "Unknown setting key '$key' in policy '$($policy.Name)'" -Level Verbose
}
}
}
}
else {
Write-PSFMessage "Policy '$($policy.Name)' has PolicySettingsBlob but no settings elements found" -Level Verbose
}
}
catch {
# Track parsing errors for reporting
$xmlParseErrors += [PSCustomObject]@{
PolicyName = $policy.Name
Error = $_.Exception.Message
}
Write-PSFMessage "Error parsing PolicySettingsBlob XML for policy '$($policy.Name)': $_" -Level Warning
}
}

# Per Microsoft documentation, disablemandatoryinoutlook can be set to explicitly
# disable mandatory labeling in Outlook even when the 'mandatory' setting is true.
# This provides an exception path for organizations that need mandatory labeling
# for files but not emails. Apply the override logic:
if ($policySettings.EmailMandatory -and $policySettings.EmailOverride) {
$policySettings.EmailMandatory = $false
}

# Store all policy settings
$allPolicySettings += [PSCustomObject]$policySettings

# Determine if this policy has ANY mandatory setting enabled (after applying overrides)
$hasMandatory = $policySettings.EmailMandatory -or
$policySettings.TeamworkMandatory -or
$policySettings.SiteGroupMandatory -or
$policySettings.PowerBIMandatory

if ($hasMandatory) {
$mandatoryPolicies += [PSCustomObject]$policySettings
}
}
}
catch {
Write-PSFMessage "Error parsing label policy settings: $_" -Level Error
$testResultMarkdown = "⚠️ Unable to determine mandatory labeling status due to unexpected policy settings structure: $_`n`n"
$customStatus = 'Investigate'
}

# Determine pass/fail status and message (only if no error occurred)
if ($null -eq $customStatus) {
if ($mandatoryPolicies.Count -gt 0) {
$passed = $true
$testResultMarkdown = "✅ Mandatory labeling is configured and enforced through at least one active sensitivity label policy across one or more workloads (Outlook, Teams/OneDrive, SharePoint/Microsoft 365 Groups, or Power BI).`n`n%TestResult%"
}
else {
$passed = $false

if ($enabledPolicies.Count -eq 0) {
$testResultMarkdown = "❌ No enabled sensitivity label policies were found in your tenant.`n`n%TestResult%"
}
else {
$testResultMarkdown = "❌ No sensitivity label policies require users to apply labels across any workload (emails, files, sites, groups, or Power BI content).`n`n%TestResult%"
}
}
}
}

#endregion Assessment Logic

#region Report Generation
$mdInfo = ''

# Show table whenever we have policy settings
if ($allPolicySettings.Count -gt 0) {
# Build policy table
$mdInfo += "`n`n### [Enabled label policies](https://purview.microsoft.com/informationprotection/labelpolicies)`n"
$mdInfo += "| Policy name | Email | Files/Collab | Sites/Groups | Power BI | Email override | Scope | Labels |`n"
$mdInfo += "| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |`n"

foreach ($policy in $allPolicySettings) {
$policyName = Get-SafeMarkdown -Text $policy.PolicyName
$emailIcon = if ($policy.EmailMandatory) { '✅' } else { '❌' }
$teamworkIcon = if ($policy.TeamworkMandatory) { '✅' } else { '❌' }
$siteGroupIcon = if ($policy.SiteGroupMandatory) { '✅' } else { '❌' }
$powerBIIcon = if ($policy.PowerBIMandatory) { '✅' } else { '❌' }
$overrideIcon = if ($policy.EmailOverride) { 'Yes' } else { 'No' }
$mdInfo += "| $policyName | $emailIcon | $teamworkIcon | $siteGroupIcon | $powerBIIcon | $overrideIcon | $($policy.Scope) | $($policy.LabelsCount) |`n"
}

# Build summary metrics
$emailCount = ($mandatoryPolicies | Where-Object { $_.EmailMandatory }).Count
$teamworkCount = ($mandatoryPolicies | Where-Object { $_.TeamworkMandatory }).Count
$siteGroupCount = ($mandatoryPolicies | Where-Object { $_.SiteGroupMandatory }).Count
$powerBICount = ($mandatoryPolicies | Where-Object { $_.PowerBIMandatory }).Count

$mdInfo += "`n`n### Summary`n"
$mdInfo += "| Metric | Count |`n"
$mdInfo += "| :--- | :--- |`n"
$mdInfo += "| Total enabled label policies | $($allPolicySettings.Count) |`n"
$mdInfo += "| Total enabled label policies with mandatory labeling | $($mandatoryPolicies.Count) |`n"
$mdInfo += "| Email mandatory labeling | $emailCount |`n"
$mdInfo += "| File/collaboration mandatory labeling | $teamworkCount |`n"
$mdInfo += "| Site/group mandatory labeling | $siteGroupCount |`n"
$mdInfo += "| Power BI mandatory labeling | $powerBICount |"
}

# Report XML parsing errors if any occurred
if ($xmlParseErrors.Count -gt 0) {
$mdInfo += "`n`n### ⚠️ XML Parsing Errors`n"
$mdInfo += "The following policies could not be parsed and were excluded from analysis:`n`n"
$mdInfo += "| Policy Name | Error |`n"
$mdInfo += "| :--- | :--- |`n"
foreach ($error in $xmlParseErrors) {
$errorMsg = Get-SafeMarkdown -Text $error.Error
$policyName = Get-SafeMarkdown -Text $error.PolicyName
$mdInfo += "| $policyName | $errorMsg |`n"
}
$mdInfo += "`n**Note**: These policies were treated as having no mandatory labeling configured.`n"
}

$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
#endregion Report Generation

$params = @{
TestId = '35016'
Title = 'Mandatory labeling enabled for sensitivity labels'
Status = $passed
Result = $testResultMarkdown
}

# Add CustomStatus if status is 'Investigate'
if ($null -ne $customStatus) {
$params.CustomStatus = $customStatus
}

Add-ZtTestResultDetail @params
}