microsoft / microsoft/CSS-Exchange

[Work Item] Health Checker: Detect Exchange Well Known Security Groups with incorrect GroupType (non-Universal)

Open
#2,557 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Health Checker P1 Work Item
Dominant language
PowerShell
Stars
1.3k
Forks
395
Avg merge
14h 7m
Merged PRs (30d)
5

Description

Describe the problem

Exchange Well Known Security Groups (e.g., Organization Management, Exchange Servers, Exchange Trusted Subsystem) are required to be Universal Security Groups for RBAC to function correctly. If an administrator or tool changes the group type (e.g., to Global or Domain Local), RBAC breaks and Exchange operations fail with permission errors.

Health Checker currently collects these groups via Get-ExchangeWellKnownSecurityGroupsGet-ExchangeOtherWellKnownObjects but only retrieves WellKnownName, WellKnownGuid, DistinguishedName, RawValue, and SID. GroupType is not collected or checked.

What needs to change

1. Data Collection — Add GroupType property

Get-ExchangeWellKnownSecurityGroups.ps1 currently queries LDAP for objectSid only. It should also retrieve the groupType attribute:

# Current (line 27-28):
$entry = [ADSI]("LDAP://$($wkObject.DistinguishedName)")
$wkObject | Add-Member -MemberType NoteProperty -Name SID -Value (...)

# Proposed: also collect groupType
$groupTypeValue = $entry.Properties["groupType"].Value
$wkObject | Add-Member -MemberType NoteProperty -Name GroupType -Value $groupTypeValue

The groupType attribute is a bitmask:

  • -2147483640 = Universal Security Group (0x80000008) — expected
  • -2147483646 = Global Security Group (0x80000002) — problem
  • -2147483644 = Domain Local Security Group (0x80000004) — problem
2. Analyzer — Check GroupType and warn

In Invoke-AnalyzerExchangeInformation.ps1, after the existing membership checks (lines 315-408), add a new check that verifies all Well Known Security Groups have the correct Universal groupType:

$universalSecurityGroup = -2147483640  # 0x80000008
$wrongTypeGroups = $HealthServerObject.OrganizationInformation.WellKnownSecurityGroups |
    Where-Object { $null -ne $_.GroupType -and $_.GroupType -ne $universalSecurityGroup }

if ($wrongTypeGroups.Count -gt 0) {
    # Display Red warning for each group with wrong type
    foreach ($group in $wrongTypeGroups) {
        # Map groupType value to friendly name
        # Show: "Organization Management - GroupType: Global (expected: Universal)"
    }
}
3. Investigate RBAC impact

Before implementing, test the following scenarios on a lab server and document what breaks:

  • Change Organization Management from Universal to Global — verify RBAC failure behavior
  • Change Exchange Servers from Universal to Global — verify service impact
  • Change Exchange Trusted Subsystem from Universal to Global — verify permission failures
  • Verify whether TokenGroupsGlobalAndUniversal count changes when groups are converted
  • Document exact error messages users see when RBAC breaks from this
4. Pester tests
  • Update GetExchangeWellKnownSecurityGroups.xml mock data to include GroupType property for all 19 groups
  • Add SE Main assertion: "Exchange Security Groups GroupType" = "Passed" (all Universal)
  • Add SE Scenario test with a mock where one or more groups have wrong GroupType
    • Override mock with modified data where Organization Management has GroupType = -2147483646 (Global)
    • Assert Red warning with group name and expected vs actual type
  • Consider adding a dedicated unit test file for the GroupType validation logic
5. Related data collection

Consider whether to also collect and display:

  • member count for key groups (helps identify empty groups)
  • managedBy attribute (identifies who owns the group)
  • Whether the group is in the expected OU/container

Current code references

  • Data Collection: Diagnostics\HealthChecker\DataCollection\OrganizationInformation\Get-ExchangeWellKnownSecurityGroups.ps1 (lines 27-28 — LDAP query)
  • Well Known Object Mapping: Shared\ActiveDirectoryFunctions\Get-ExchangeOtherWellKnownObjects.ps1 (19 groups defined)
  • Analyzer: Diagnostics\HealthChecker\Analyzer\Invoke-AnalyzerExchangeInformation.ps1 (lines 315-408 — membership checks)
  • Mock Data: Diagnostics\HealthChecker\Tests\DataCollection\ExchangeSE\Exchange\GetExchangeWellKnownSecurityGroups.xml (19 groups, no GroupType property)

Additional context

The 19 default Exchange Well Known Security Groups that should all be Universal:
Organization Management, Recipient Management, View-Only Organization Management, Public Folder Management, UM Management, Help Desk, Records Management, Discovery Management, Server Management, Delegated Setup, Hygiene Management, Compliance Management, Exchange Servers, Exchange Trusted Subsystem, Managed Availability Servers, Exchange Windows Permissions, ExchangeLegacyInterop, Security Reader, Security Administrator

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Diagnostics\HealthChecker\DataCollection\OrganizationInformation\Get-ExchangeWellKnownSecurityGroups.ps1 and Invoke-AnalyzerExchangeInformation.ps1, then inspect the 19-group XML mock and existing ExchangeSE Pester tests. Reproduce the listed group-type and RBAC scenarios in a lab if available. Done means GroupType is collected, incorrect types produce a named warning, and passing and failing mock scenarios are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
powershell
Domain
security, testing-qa, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.