Reporting the Assignment of Container Management Labels

Managing Microsoft 365 Group Settings with Container Management Labels

Container management labels are sensitivity labels configured with management controls that Microsoft 365 groups and their associated SharePoint Online sites and teams inherit from labels assigned on the creation of new groups or by administrators afterward. Important settings include external sharing of SharePoint content (Figure 1) and whether guest members are allowed in groups.

Container management settings for a sensitivity label
Figure 1: Container management settings for a sensitivity label

The settings inherited from assigned labels cannot by changed by group or team owners. However, a group owner can change the effective settings for a site by choosing to apply a different container management label. An organization can monitor for label assignments to groups and reserve those changes if necessary. However, this isn’t standard functionality and must be enabled using a tool like PowerShell (here’s an example).

Container Management Labels

Sensitivity labels are available in tenants licensed with Office 365 E3 or above. If you’re in this position, container management labels are an excellent way to ensure consistency in group settings. An organization can deploy and use container management labels even if they don’t use sensitivity labels for information protection and document marking. In fact, even though it’s possible to use the same set of sensitivity labels for both purposes, it’s a good idea to maintain two sets of labels: one for container management and the other for information protection.

Checking Container Management Label Assignments

Two PowerShell methods are available to check group information:

  • The Get-UnifiedGroup cmdlet from the Exchange Online management module.
  • The Get-MgGroup cmdlet from the Microsoft Graph PowerShell SDK.

Because it must fetch information for many aspects of a Microsoft 365 group, Get-UnifiedGroup is a “heavy” cmdlet. The cmdlet will find all groups, but it will be slow. Get-MgGroup is faster because it retrieves fewer properties for each group. The downside is that Get-MgGroup doesn’t include sensitivity labels in its set of properties. A separate Graph call is required to fetch the label assigned to a group.

To illustrate the point, this code finds all Microsoft 365 groups in a tenant and highlights any group that doesn’t have an assigned sensitivity label.

Connect-MgGraph -Scopes Directory.Read.All

Write-Host "Finding Microsoft 365 Groups to process..."
[array]$Groups = Get-MgGroup -Filter "groupTypes/any(c:c eq 'unified')" -All
If (!($Groups)) { Write-Host "Whoops - can't find any Microsoft 365 Groups" ; break }

ForEach ($Group in $Groups) {
 $LabelId = $Null; $LabelName = $Null

 $Uri = ("https://graph.microsoft.com/v1.0/groups/{0}?`$select=assignedLabels" -f $Group.Id)
 $LabelData = Invoke-GraphRequest -Uri $Uri
 $LabelName = $LabelData.assignedLabels.displayName
 $LabelId   = $LabelData.assignedLabels.labelId
 [array]$GroupOwners = Get-MgGroupOwner -GroupId $Group.Id
 $GroupOwnerNames = $GroupOwners.additionalProperties.displayName -join ", "
 If (!($LabelName)) {
    Write-Host ("The {0} group has no label. Owner(s) {1}" -f $Group.displayName, $GroupOwnerNames) -foregroundcolor Red
 } }
}

By contrast, Get-UnifiedGroup includes sensitivity label data in its properties. However, the property holds the GUID for an assigned sensitivity label instead of its display name. Some additional effort is required to resolve the label GUID to a display name by first fetching the set of sensitivity labels in the tenant (with the Get-Label cmdlet) and building a table of GUIDs and display names to lookup.

This code illustrates how to use the Get-UnifiedGroup cmdlet to accomplish the same goal:

Write-Host "Finding Microsoft 365 Groups to process..."
[array]$Groups = Get-UnifiedGroup -ResultSize Unlimited
If (!($Groups)) { Write-Host "Whoops - can't find any Microsoft 365 Groups" ; break }

ForEach ($Group in $Groups) {
 [array]$GroupOwnerNames = $Null; $LabelId = $Null; $LabelName = $Null

 $LabelId = $Group.SensitivityLabel.Guid
 If ($LabelId) {
   $LabelName = $LabelHash[$LabelId] }

 [array]$GroupOwners = $Group.ManagedBy
 ForEach ($Owner in $GroupOwners) {
    [string]$Owner = $Owner
    $GroupOwnerNames += (Get-Mailbox -Identity $Owner -ErrorAction SilentlyContinue).DisplayName }
 [string]$GroupOwnerNames = $GroupOwnerNames -join ", "
 If (!($LabelName)) {
    Write-Host ("The {0} group has no label. Owner(s) {1}" -f $Group.displayName, $GroupOwnerNames) -foregroundcolor Red
 }
}

The code doesn’t include the commands to connect to Exchange Online and the compliance endpoint (to get label information), nor does it include the code to build the hash table used for label lookups. These commands add about ten seconds of overhead. This isn’t usually a problem.

Testing against 250 groups, the Get-MgGroup method took 1 minute 12 seconds while Get-UnifiedGroup took 1 minute 28 seconds. Generally speaking, Graph-based cmdlets are always faster than the more complex cmdlets used by workloads like Exchange, especially when running at scale against thousands of objects.

Completing the Job

After deciding which approach to use, to finish the job, we put the results of the scan into a PowerShell list and generate a report. The final result is a little more complicated than the processing described above to format the output (Figure 2) and include some additional sections like listing groups that don’t have a label, groups that don’t have any owners, and summary data like how many assignments to groups for each label.

Reporting Container Management labels for Microsoft 365 groups
Figure 2: Reporting Container Management labels for Microsoft 365 groups

The final script is available from GitHub. Feel free to improve the output!


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

7 Replies to “Reporting the Assignment of Container Management Labels”

  1. HI Tony,

    Thanks for your scripts they have been very helpful. I was trying to add Customattribute14 to the report but I haven’t been able to, Please how do I add a tab for customattribute 14.

    Thanks

    1. Instead of:

      $ReportLine = [PSCustomObject][Ordered]@{
      Id = $Group.Id
      Name = $Group.DisplayName
      Owners = $GroupOwnerNames
      Label = $LabelName
      LabelId = $LabelId
      Status = $Status }

      Use:
      $ReportLine = [PSCustomObject][Ordered]@{
      Id = $Group.Id
      Name = $Group.DisplayName
      Owners = $GroupOwnerNames
      Label = $LabelName
      LabelId = $LabelId
      State = $Group.CustomAttribute14
      Status = $Status }
      $Report.Add($ReportLine)

      1. The problem (which I should have noticed) is that the script uses Get-MgGroup to find Microsoft 365 groups. Get-MgGroup doesn’t return the on-premises extension attributes like Get-MgUser does. In any case, I updated the code in your fork to use the Get-UnifiedGroup cmdlet instead. It works now.

  2. Hey, Thanks for your response. I can’t seem to see any changes by you. The last changes was done by me 3hrs ago.. Did you forget to push 🙂

  3. HI Tony

    Thanks I saw the changes you made. I tried similar but kept missing bits but all good with your help “).. Thanks for your help .. I also added a summary for mismatch label that compares _.LabelId -ne $Group.CustomAttribute14 Hopefully someone else will need it.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.