Achieve Consistency for Groups, Teams, and Sites

In June 2020, support for container management through sensitivity labels became generally available. In a nutshell, label settings can control aspects like guest access, privacy, and the sharing capability for SharePoint Online sites. It’s a very powerful and practical way for organizations to apply consistent settings to Microsoft 365 groups, teams, and SharePoint sites.

Some recent work to improve the Teams and Groups activity report script revealed that some groups in my tenant didn’t have sensitivity labels. It seemed like the groups for org-wide teams and Yammer communities were most of the culprits, but I decided that it would be good to apply a default label to all groups without a label. This is reasonably easy with PowerShell. Here’s the code I used:

$DefaultSensitivityLabel = "e42fd42e-7240-4df0-9d8f-d14658bcf7ce" # Guid for General Access
$LabelsAssigned = 0

Write-Host "Fetching Microsoft Groups"
$Groups = Get-UnifiedGroup -ResultSize Unlimited
ForEach ($Group in $Groups) {
   If ($Group.SensitivityLabel -eq $Null) { # No label assigned so let's assign the default label
      Write-Host $Group.DisplayName "has no sensitivity label - assigning the default label" -Foregroundcolor Red
      Set-UnifiedGroup -Identity $Group.ExternalDirectoryObjectId -SensitivityLabel $DefaultSensitivityLabel -CustomAttribute14 $DefaultSensitivityLabel
      $LabelsAssigned++
      }
   Else { # Just update the Custom Attribute
      Set-UnifiedGroup -Identity $Group.ExternalDirectoryObjectId  -CustomAttribute14 $Group.SensitivityLabel
   }
} # End For

Write-Host ("Labels assigned to {0} Microsoft 365 Groups; updated label tracking attribute for {1} groups" -f $LabelsAssigned, $Groups.Count)

Setting a Baseline for Container Labels

Apart from assigning a default label to groups, I use one of the fifteen custom attributes available for mail-enabled objects to store details of the assigned label. The reason why is simple. An organization might assign a sensitivity label to a container, but the Microsoft 365 groups model allows group owners great power over settings, and there’s no way to lock a sensitivity label on a container. Changes to group settings made via an application like Teams or SharePoint Online synchronize with other workloads to make sure that a common view exists across all workloads.

The upshot is that if an organization wants to exert control over group settings, some mechanism must be put in place to check those settings periodically to make sure that group owners haven’t made changes which clash with corporate norms. Storing the assigned label in a custom attribute establishes a baseline that can be checked against. The periodic check can compare the currently assigned label for each group to the one noted in the custom attribute. If a mismatch exists, it can be flagged for action.

Building a List of Container Management Labels

The first thing we’ll do is to build a list of sensitivity labels used for container management. Groups, teams, and sites store label identifiers (GUIDs) for assigned labels. This makes sense because a GUID won’t change while a display name for a sensitivity label might (also, display names can have multiple language values). This code creates a list of container management labels, including the priority of each label. The priority tells us how sensitive a label is. A label with priority 0 (zero) is the least sensitive of any in the organization. By comparing the priority of the original label and a newly assigned label, we can tell if a label replacement is more or less sensitive.

Labels = Get-Label
$ContainerLabels = [System.Collections.Generic.List[Object]]::new() 
ForEach ($Label in $Labels) { 
    If ($Label.ContentType -Like "*UnifiedGroup*") { # It's a label for container management
      $DataLine = [PSCustomObject] @{
        LabelId     = $Label.ImmutableId
        DisplayName = $Label.DisplayName
        Priority    = $Label.Priority } 
      $ContainerLabels.Add($DataLine) }
}

You must connect to the compliance endpoint to access label information. The easiest way to do this is to connect to the Exchange Online management module and then use the same credentials with the Connect-IPPSession cmdlet.

Checking Groups for Label Changes

The check for label changes is performed by looping through the set of groups to compare the originally assigned label (stored in CustomAttribute14) against the currently assigned label. If a mismatch is found, we capture the information about the old and new labels and figure out if sensitivity is increased or decreased.

Write-Host "Fetching Microsoft Groups"
$Groups = Get-UnifiedGroup -ResultSize Unlimited
$ReviewGroups = [System.Collections.Generic.List[Object]]::new() 
ForEach ($Group in $Groups) {
   If ([guid]$Group.SensitivityLabel.Guid -ne [guid]$Group.CustomAttribute14) { # We have a mismatch
    Write-Host "Label mismatch discovered for" $Group.DisplayName
    $OldLabelGuid = $Group.CustomAttribute14
    $NewLabelGuid = $Group.SensitivityLabel       
    $OldLabelName = $ContainerLabels | ? {$_.LabelId -eq $OldLabelGuid} | Select -ExpandProperty DisplayName
    $NewLabelName = $ContainerLabels | ? {$_.LabelId -eq $NewLabelGuid} | Select -ExpandProperty DisplayName
    $OldPriority  = $ContainerLabels | ? {$_.LabelId -eq $OldLabelGuid} | Select -Expandproperty Priority
    $NewPriority  = $ContainerLabels | ? {$_.LabelId -eq $NewLabelGuid} | Select -ExpandProperty Priority
    If ($OldPriority -gt $NewPriority) { $LabelStatus = "Sensitivity Label Priority Reduced" }
    Else { $LabelStatus = "Sensitivity Label Priority Increased"}
    $DataLine = [PSCustomObject] @{
        Group       = $Group.DisplayName
        GroupId     = $Group.ExternalDirectoryObjectId
        OldLabel    = $OldLabelName
        OldLabelId  = $OldLabelGuid
        NewLabel    = $NewLabelName
        OldPriority = $OldPriority
        NewPriority = $NewPriority
        Status      = $LabelStatus }    $ReviewGroups.Add($DataLine) }
   }

Deciding How to Deal with Label Changes

Two obvious approaches could be taken if the original sensitivity label changes:

  • Check and query. It’s possible that an administrator or group/team owner changes the label for a good reason. For example, the original label blocked guest access and it is subsequently discovered that guest access is needed. To confirm, you could send email to group owners to ask why the label changed. Alternatively, tenant administrators could review the set of label changes and decide which are appropriate and which should be reversed.
  • Check and revert. This is the hard-line approach. The original label is the label and group owners aren’t allowed to change it, so the original label is reapplied.

In the first instance, it should be enough to save the output list to a CSV file and use it as the basis for communication with group owners. Something like this will do the job:

$ReviewGroups | Export-CSV -NoTypeInformation c:\Temp\ReviewGroups.csv

But if we want to restore the original sensitivity label, we can use code like that shown below to list the set of containers with replacement labels and prompt to revert. If a positive answer is given, we reapply the label GUID stored in CustomAttribute14 (Figure 1).

Deciding whether to restore the original sensitivity labels to containers
Figure 1: Deciding whether to restore the original sensitivity labels to containers
If (!($ReviewGroups)) {Write-Host "All good. No label mismatches discovered"; break}

CLS 
$ReviewGroups | Format-Table Group, OldLabel, NewLabel, Status -AutoSize
$PromptTitle = 'Restore original sensitivity label to groups'
$PromptMessage = 'Please confirm whether to go ahead and restore the original sensitivity label to these groups'
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&yes", 'yes?'
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&no", 'no?'
$cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&cancel", 'Exit'
$PromptOptions = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $cancel)
$PromptDecision = $host.ui.PromptForChoice($PromptTitle, $PromptMessage, $PromptOptions, 0) 
$i = 0
# Decision made Y or default to go ahead and restore the labels, so let's do it.
If ($PromptDecision -eq 0) {
   ForEach ($G in $ReviewGroups) {
     Write-Host "Restoring sensitivity label to" $G.Group
     Set-UnifiedGroup -Identity $G.GroupId -SensitivityLabel $G.CustomAttribute14
     $i++ }
   Write-Host "All done. Sensitivity Labels restored for $i containers" }
Else {
   Write-Host "OK. Details of the containers are in c:\temp\ReviewGroups.csv"
   $ReviewGroups | Export-CSV -NoTypeInformation c:\temp\ReviewGroups.csv }

Some More Work to Do

If the option to restore labels is chosen, the script restores the original labels. However, applying a label to a container only affects future behavior. It does nothing to deal with anything which happened in the past. For instance, if an owner changed the label to allow guest access and then added some guests, reapplying a label which blocks guest access does not remove the guests and they retain access to group resources until they are removed from group membership. It is therefore a good idea to include a check for guest members if labels change.

One way to approach the issue is to check the reapplied label to see if its settings allow guest access. If it doesn’t, check the count of guests in the group membership (stored in the group’s GroupExternalMemberCount property), and flag an error if this is non-zero. Optionally, you could then go ahead and remove guest members using the Remove-UnifiedGroupLinks cmdlet. All possible in a few extra lines of PowerShell.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Comments

  1. Dave

    Regarding the first section of your article about labeling groups without a label – how did you handle labeling SPO sites that aren’t associated with any 365 groups?

    1. Avatar photo
      Tony Redmond

      I don’t. But it’s PowerShell and you can use the Get-SPOSite cmdlet to get the sensitivity label data and check if it changes.

  2. Lance

    Hi Tony,
    Great blog and I have also come across the same issues.

    Have you had a thought about misclassification from the Team creation and the underlying SharePoint site? When a Team is created with a container label the SharePoint site is also applied with the same label. But changing the classification of the Team the SharePoint site doesn’t follow.

    If you created the Team with say an external label to allow guests etc then change it to an Internal label. The guest would still have full access to the underlying SharePoint site as long as they are not removed from the Unified Group.
    If removed from the group they would lose the access but the SharePoint site is still open to guests.

    I find it strange that when you change a classification on the Team the underpinning Site doesn’t follow.

    What are your thoughts on this?

    Many Thanks

    Lance

    1. Avatar photo
      Tony Redmond

      It takes time for the synchronization of a label change (made in Teams or OWA) to reach SharePoint Online. I believe the expected period is up to 24 hours. During that time, SPO will display an incorrect label. If this is important, go and change the label in the SPO admin center.

Leave a Reply