From f71cd3f61bca9ea763e602543cd2a8d4bff09c45 Mon Sep 17 00:00:00 2001 From: Manoj K Date: Fri, 9 Jan 2026 08:15:28 +0530 Subject: [PATCH 1/9] Feature-35015 --- src/powershell/tests/Test-Assessment.35015.md | 30 +++++ .../tests/Test-Assessment.35015.ps1 | 123 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/powershell/tests/Test-Assessment.35015.md create mode 100644 src/powershell/tests/Test-Assessment.35015.ps1 diff --git a/src/powershell/tests/Test-Assessment.35015.md b/src/powershell/tests/Test-Assessment.35015.md new file mode 100644 index 000000000..ec8f28a3e --- /dev/null +++ b/src/powershell/tests/Test-Assessment.35015.md @@ -0,0 +1,30 @@ +Sensitivity label policies control which labels are available to users and can be scoped to specific users, groups, or the entire organization. Publishing too many labels globally creates confusion and decision paralysis for end users, reducing adoption and increasing the likelihood of misclassification. When users are presented with an overwhelming number of label choices (typically more than 25 top-level and sub-labels), they struggle to identify the appropriate classification for their content, leading to either selecting incorrect labels or avoiding the feature entirely. + +Microsoft recommends publishing no more than 25 labels in globally-scoped policies, ideally organized as 5 parent labels with up to 5 sub-labels each. This creates a manageable hierarchy that users can understand and apply consistently. Organizations with complex classification needs should use scoped policies to publish specialized labels only to the departments or roles that require them, keeping the global label set lean and focused on the most common classification scenarios. + +**Remediation action** + +To reduce the number of globally-published labels: +1. Review which labels are truly needed by all users +2. Create scoped label policies for department-specific or role-specific labels +3. Remove less-commonly-used labels from global policies +4. Consolidate similar labels where possible +5. Use sub-labels to organize related labels under parent categories + +Best practices: +- Limit global policies to 5-7 top-level labels with 3-5 sub-labels each +- Use clear, business-friendly label names (not technical jargon) +- Publish specialized labels only to users who need them via scoped policies + +To manage label policies: +1. Navigate to [Microsoft Purview portal > Information Protection > Label policies](https://purview.microsoft.com/informationprotection/labelpolicies) +2. Review existing globally-scoped policies +3. Edit policies to remove unnecessary labels or change scope to specific users/groups +4. Create new scoped policies for specialized labels + +- [Sensitivity label policies best practices](https://learn.microsoft.com/purview/sensitivity-labels#what-label-policies-can-do) +- [Create and publish sensitivity labels](https://learn.microsoft.com/microsoft-365/compliance/create-sensitivity-labels) +- [Label policy priority and precedence](https://learn.microsoft.com/purview/sensitivity-labels-office-apps#label-policy-priority-order-matters) + + +%TestResult% diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 new file mode 100644 index 000000000..fcef88fd6 --- /dev/null +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -0,0 +1,123 @@ +<# +.SYNOPSIS + Global Scope Label Count + +.DESCRIPTION + Sensitivity label policies control which labels are available to users and can be scoped to specific users, groups, or the entire organization. Publishing too many labels globally creates confusion and decision paralysis for end users. Microsoft recommends publishing no more than 25 labels in globally-scoped policies to maintain usability and reduce misclassification. + +.NOTES + Test ID: 35015 + Pillar: Data + Risk Level: Medium +#> + +function Test-Assessment-35015 { + [ZtTest( + Category = 'Information Protection', + ImplementationCost = 'Low', + MinimumLicense = ('Microsoft 365 E3'), + Pillar = 'Data', + RiskLevel = 'Medium', + SfiPillar = '', + TenantType = ('Workforce'), + TestId = 35015, + Title = 'Global Scope Label Count', + UserImpact = 'High' + )] + [CmdletBinding()] + param() + + #region Data Collection + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose + + $activity = 'Checking Global Scope Label Count' + Write-ZtProgress -Activity $activity -Status 'Getting label policies' + + $errorMsg = $null + $maxRecommendedLabels = 25 + + try { + # Get all enabled label policies + $labelPolicies = 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 + $customStatus = $null + if ($errorMsg) { + $passed = $false + $customStatus = 'Investigate' + } + else { + # Identify globally-scoped policies (no specific user/group scope or applies to 'All') + $globalPolicies = $labelPolicies | Where-Object { + ($policy.ExchangeLocation -contains 'All') -or + ((-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and + (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0)) + } + + # Count unique labels across all global policies + $uniqueLabels = $globalPolicies.Labels | Where-Object { $_ } | Select-Object -Unique + $totalUniqueLabels = $uniqueLabels.Count + $passed = $totalUniqueLabels -le $maxRecommendedLabels + } + #endregion Assessment Logic + + #region Report Generation + if ($errorMsg) { + $testResultMarkdown = "### Investigate`n`n" + $testResultMarkdown += "Unable to determine global label count due to error: $errorMsg" + } + else { + $status = if ($passed) { '✅' } else { '❌' } + $statusText = if ($passed) { 'within' } else { 'exceeding' } + $testResultMarkdown = "$status $totalUniqueLabels sensitivity labels are published in globally-scoped policies, $statusText the recommended limit of $maxRecommendedLabels.`n`n" + + if ($globalPolicies) { + $testResultMarkdown += "### Global Label Policies`n`n" + $testResultMarkdown += "| Policy Name | Status | Labels Published | Sample Labels |`n" + $testResultMarkdown += "| :--- | :--- | :---: | :--- |`n" + + $policyLink = "https://purview.microsoft.com/informationprotection/labelpolicies" + + foreach ($policy in $globalPolicies) { + $policyName = Get-SafeMarkdown -Text $policy.Name + $labelCount = @($policy.Labels).Count + + # Get sample labels (up to 5) + $sampleLabels = if ($policy.Labels) { + $samples = @($policy.Labels | Select-Object -First 5) + $labelText = ($samples | ForEach-Object { Get-SafeMarkdown -Text $_ }) -join ', ' + if (@($policy.Labels).Count -gt 5) { $labelText += '...' } + $labelText + } else { 'None' } + + $testResultMarkdown += "| [$policyName]($policyLink) | Enabled | $labelCount | $sampleLabels |`n" + } + + $statusText = if ($passed) { 'Pass' } else { 'Fail' } + $testResultMarkdown += "`n### Summary`n`n" + $testResultMarkdown += "* **Total Unique Labels Published Globally:** $totalUniqueLabels`n" + $testResultMarkdown += "* **Recommended Maximum:** $maxRecommendedLabels`n" + $testResultMarkdown += "* **Status:** $statusText`n" + } else { + $testResultMarkdown += "No globally-scoped label policies found.`n" + } + } + #endregion Report Generation + + $params = @{ + TestId = '35015' + Title = 'Global Scope Label Count' + Status = $passed + Result = $testResultMarkdown + } + if ($customStatus) { + $params.CustomStatus = $customStatus + } + Add-ZtTestResultDetail @params +} From 4330808f90c4b02473dffec60e3c733910574f2b Mon Sep 17 00:00:00 2001 From: Manoj Kesana Date: Fri, 9 Jan 2026 16:08:21 +0530 Subject: [PATCH 2/9] Update src/powershell/tests/Test-Assessment.35015.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.35015.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index fcef88fd6..0051897ab 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -55,7 +55,7 @@ function Test-Assessment-35015 { else { # Identify globally-scoped policies (no specific user/group scope or applies to 'All') $globalPolicies = $labelPolicies | Where-Object { - ($policy.ExchangeLocation -contains 'All') -or + ($_.ExchangeLocation -contains 'All') -or ((-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0)) } From 93044586b168ea09c58a0d3ef0348f90454103e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:39:51 +0000 Subject: [PATCH 3/9] Initial plan From 127efe7412af5c214a5ab04a4116eb84dbdc4dff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:42:03 +0000 Subject: [PATCH 4/9] Fix global policy scope detection logic to check all location properties Co-authored-by: Manoj-Kesana <232508253+Manoj-Kesana@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.35015.ps1 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index 0051897ab..ef1d76804 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -55,9 +55,16 @@ function Test-Assessment-35015 { else { # Identify globally-scoped policies (no specific user/group scope or applies to 'All') $globalPolicies = $labelPolicies | Where-Object { - ($_.ExchangeLocation -contains 'All') -or - ((-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and - (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0)) + ($_.ExchangeLocation -contains 'All') -or + ($_.ModernGroupLocation -contains 'All') -or + ($_.SharePointLocation -contains 'All') -or + ($_.OneDriveLocation -contains 'All') -or + ( + (-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and + (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0) -and + (-not $_.SharePointLocation -or $_.SharePointLocation.Count -eq 0) -and + (-not $_.OneDriveLocation -or $_.OneDriveLocation.Count -eq 0) + ) } # Count unique labels across all global policies From 910ec47cbf79ab4caad5737f0dff171559f102aa Mon Sep 17 00:00:00 2001 From: Manoj K Date: Thu, 15 Jan 2026 09:37:47 +0530 Subject: [PATCH 5/9] Fixed Logic --- src/powershell/tests/Test-Assessment.35015.ps1 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index ef1d76804..4a3f39b35 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -55,10 +55,10 @@ function Test-Assessment-35015 { else { # Identify globally-scoped policies (no specific user/group scope or applies to 'All') $globalPolicies = $labelPolicies | Where-Object { - ($_.ExchangeLocation -contains 'All') -or - ($_.ModernGroupLocation -contains 'All') -or - ($_.SharePointLocation -contains 'All') -or - ($_.OneDriveLocation -contains 'All') -or + ($_.ExchangeLocation -like 'All') -or + ($_.ModernGroupLocation -like 'All') -or + ($_.SharePointLocation -like 'All') -or + ($_.OneDriveLocation -like 'All') -or ( (-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0) -and @@ -66,8 +66,6 @@ function Test-Assessment-35015 { (-not $_.OneDriveLocation -or $_.OneDriveLocation.Count -eq 0) ) } - - # Count unique labels across all global policies $uniqueLabels = $globalPolicies.Labels | Where-Object { $_ } | Select-Object -Unique $totalUniqueLabels = $uniqueLabels.Count $passed = $totalUniqueLabels -le $maxRecommendedLabels From 076a3b51b588ce905ffe10d1f75806a39c2f43ef Mon Sep 17 00:00:00 2001 From: Manoj Kesana Date: Fri, 16 Jan 2026 09:55:20 +0530 Subject: [PATCH 6/9] Update src/powershell/tests/Test-Assessment.35015.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.35015.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index 4a3f39b35..3cd121ff3 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -55,10 +55,10 @@ function Test-Assessment-35015 { else { # Identify globally-scoped policies (no specific user/group scope or applies to 'All') $globalPolicies = $labelPolicies | Where-Object { - ($_.ExchangeLocation -like 'All') -or - ($_.ModernGroupLocation -like 'All') -or - ($_.SharePointLocation -like 'All') -or - ($_.OneDriveLocation -like 'All') -or + ($_.ExchangeLocation -contains 'All') -or + ($_.ModernGroupLocation -contains 'All') -or + ($_.SharePointLocation -contains 'All') -or + ($_.OneDriveLocation -contains 'All') -or ( (-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0) -and From 0dc80ef8af44603ecb0bcb72871e77e820ae9f25 Mon Sep 17 00:00:00 2001 From: Manoj Kesana Date: Fri, 16 Jan 2026 09:55:31 +0530 Subject: [PATCH 7/9] Update src/powershell/tests/Test-Assessment.35015.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.35015.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index 3cd121ff3..8e8988513 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -97,7 +97,7 @@ function Test-Assessment-35015 { $sampleLabels = if ($policy.Labels) { $samples = @($policy.Labels | Select-Object -First 5) $labelText = ($samples | ForEach-Object { Get-SafeMarkdown -Text $_ }) -join ', ' - if (@($policy.Labels).Count -gt 5) { $labelText += '...' } + if (@($policy.Labels).Count -gt 5) { $labelText += ', ...' } $labelText } else { 'None' } From df1fbc7850ff9a0d6222cfe12f3aab0851bb567e Mon Sep 17 00:00:00 2001 From: Manoj Kesana Date: Fri, 16 Jan 2026 09:55:42 +0530 Subject: [PATCH 8/9] Update src/powershell/tests/Test-Assessment.35015.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/powershell/tests/Test-Assessment.35015.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index 8e8988513..49402c22b 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -67,7 +67,7 @@ function Test-Assessment-35015 { ) } $uniqueLabels = $globalPolicies.Labels | Where-Object { $_ } | Select-Object -Unique - $totalUniqueLabels = $uniqueLabels.Count + $totalUniqueLabels = @($uniqueLabels).Count $passed = $totalUniqueLabels -le $maxRecommendedLabels } #endregion Assessment Logic From 75ea20f10144d454642dfb9b2262c9fe9b2861cb Mon Sep 17 00:00:00 2001 From: Manoj K Date: Wed, 28 Jan 2026 16:11:46 +0530 Subject: [PATCH 9/9] Fix Label region code --- .../tests/Test-Assessment.35015.ps1 | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/powershell/tests/Test-Assessment.35015.ps1 b/src/powershell/tests/Test-Assessment.35015.ps1 index 49402c22b..0657cae88 100644 --- a/src/powershell/tests/Test-Assessment.35015.ps1 +++ b/src/powershell/tests/Test-Assessment.35015.ps1 @@ -53,19 +53,22 @@ function Test-Assessment-35015 { $customStatus = 'Investigate' } else { - # Identify globally-scoped policies (no specific user/group scope or applies to 'All') - $globalPolicies = $labelPolicies | Where-Object { - ($_.ExchangeLocation -contains 'All') -or - ($_.ModernGroupLocation -contains 'All') -or - ($_.SharePointLocation -contains 'All') -or - ($_.OneDriveLocation -contains 'All') -or - ( - (-not $_.ModernGroupLocation -or $_.ModernGroupLocation.Count -eq 0) -and - (-not $_.ExchangeLocation -or $_.ExchangeLocation.Count -eq 0) -and - (-not $_.SharePointLocation -or $_.SharePointLocation.Count -eq 0) -and - (-not $_.OneDriveLocation -or $_.OneDriveLocation.Count -eq 0) - ) - } + # Identify globally-scoped policies by checking all location names + $globalPolicies = $labelPolicies | ForEach-Object { + $policy = $_ + $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' + $scope = if ($isGlobal) { 'Global' } else { 'User/Group-Scoped' } + + $policy | Add-Member -MemberType NoteProperty -Name 'Scope' -Value $scope -PassThru + } | Where-Object { $_.Scope -eq 'Global' } $uniqueLabels = $globalPolicies.Labels | Where-Object { $_ } | Select-Object -Unique $totalUniqueLabels = @($uniqueLabels).Count $passed = $totalUniqueLabels -le $maxRecommendedLabels @@ -84,13 +87,14 @@ function Test-Assessment-35015 { if ($globalPolicies) { $testResultMarkdown += "### Global Label Policies`n`n" - $testResultMarkdown += "| Policy Name | Status | Labels Published | Sample Labels |`n" - $testResultMarkdown += "| :--- | :--- | :---: | :--- |`n" + $testResultMarkdown += "| Policy Name | Status | Scope | Labels Published | Sample Labels |`n" + $testResultMarkdown += "| :--- | :--- | :--- | :---: | :--- |`n" $policyLink = "https://purview.microsoft.com/informationprotection/labelpolicies" foreach ($policy in $globalPolicies) { $policyName = Get-SafeMarkdown -Text $policy.Name + $scope = $policy.Scope $labelCount = @($policy.Labels).Count # Get sample labels (up to 5) @@ -101,7 +105,7 @@ function Test-Assessment-35015 { $labelText } else { 'None' } - $testResultMarkdown += "| [$policyName]($policyLink) | Enabled | $labelCount | $sampleLabels |`n" + $testResultMarkdown += "| [$policyName]($policyLink) | Enabled | $scope | $labelCount | $sampleLabels |`n" } $statusText = if ($passed) { 'Pass' } else { 'Fail' }