Microsoft 365 Email & Collaboration

Implementing Microsoft Teams Governance: Naming Policies, Expiration, Access Reviews, and Sensitivity Labels

Every Team is a Microsoft 365 Group. That single fact is the whole governance story. When a user clicks “Create team,” they are not creating a chat app — they are provisioning a Microsoft 365 Group, and Microsoft 365 fans out a connected mailbox, a SharePoint site, a OneNote, a Planner plan, and a membership/owner list, all bound to that one group object. The group is the identity, the membership, the lifecycle anchor, and the security boundary. Govern the group and you govern the Team, the files, the channels, the guests, and the expiration — all at once. Govern only “Teams” and you are governing a workload while the object underneath it sprawls unchecked.

This is why uncontrolled Teams adoption becomes a governance crisis so fast. In a tenant with self-service creation left on, a 5,000-seat organization routinely accumulates 8,000–15,000 Microsoft 365 Groups inside eighteen months: duplicate “Project Phoenix” teams, single-message teams created for a meeting that never recurred, teams whose only owner left the company two reorganizations ago, teams full of external guests nobody remembers inviting, and teams holding regulated data with external sharing wide open. None of that is a Teams problem. It is a group lifecycle problem wearing a Teams costume, and it is solved with five interlocking controls that all operate on the Microsoft 365 Group: a naming policy, an expiration policy, a creation restriction, container sensitivity labels, and guest access reviews.

This guide builds that control plane end to end — in Entra ID directory settings, Microsoft Graph PowerShell, Microsoft Purview, and Entra ID Governance. It enumerates every option, value, default, and gotcha for each control, lays the reference material out as scannable tables you keep open during a rollout, and sequences the whole thing into a staged program that pilots each control before it goes tenant-wide. By the end you will understand not just how to set a naming policy or publish a container label, but why these five controls are one system — and how they fail catastrophically when you treat them as five independent projects.

What problem this solves

Self-service collaboration is the entire value proposition of Teams: a user has a need, creates a space in ten seconds, and the work happens. Take that away with heavy-handed governance and people route around you — they collaborate in personal OneDrive, in a consumer WhatsApp group, in email attachments flying to external addresses, in shadow tenants. So the goal is never to stop creation; it is to make self-service safe and legible — every team named consistently, owned by a human, classified by sensitivity, lifecycle-bounded, and with guests that get re-attested rather than accumulated forever.

What breaks without this, concretely. Sprawl: ten thousand groups, most dormant, drowning legitimate ones in search and in the Teams left rail, and inflating your SharePoint storage and backup footprint. Ownerless data: groups whose owners left, so nobody can manage membership, approve a guest, or respond to a renewal prompt — the data is stranded and unmanageable. Unclassified regulated data: a team holding M&A documents or PII with external sharing on “anyone with the link,” because the user who made it never thought about classification and nothing forced them to. Guest accumulation: a partner’s three contractors invited two years ago, the project long finished, still members with standing access to the SharePoint site. Naming chaos: forty teams called “Marketing,” “marketing-team,” “Mktg Final,” impossible to find or audit. Each of these is a real incident waiting in a compliance audit, a data-loss event, or a help-desk queue.

Who hits this: every organization that turned on Teams (which is everyone) and left the defaults (which is most of them). It bites hardest in regulated industries (finance, healthcare, government) where unclassified or externally-shared data is a reportable event; in organizations with heavy external collaboration (consulting, manufacturing supply chains) where guest sprawl is the dominant risk; and in any tenant past ~2,000 seats where the sheer volume makes manual cleanup impossible and only policy scales. The fix is to recognize the Microsoft 365 Group as the single object all five controls act on, then build them in the right order.

To frame the whole field before the deep dive, here is every governance concern this article covers, where its control actually lives, and what tool configures it:

Governance concern What it controls Where the control lives Primary tooling License floor
Naming consistency Prefix/suffix + blocked words on group name and alias Entra ID directory setting Group.Unified Graph PowerShell / Entra admin center Entra ID P1 (per member)
Lifecycle / sprawl Expiration lifetime + renewal of inactive groups Microsoft 365 Groups expiration policy Entra admin center / Graph Entra ID P1 (per member)
Who can create Restrict group/Team creation to a security group Entra ID directory setting Group.Unified Graph PowerShell Entra ID P1 (per member)
Privacy, guest, device, sharing Container behaviors on the group + SharePoint site Container sensitivity labels Microsoft Purview + Graph Purview Information Protection
Guest lifecycle Recurring re-attestation; auto-remove stale guests Access reviews Entra ID Governance (P2) Entra ID P2 / Governance SKU
Guest invitation Who may invite; allowed/blocked domains External collaboration / cross-tenant access Entra admin center Entra ID Free+
Ownerless / drift Detect under-owned groups; reassign ownership Ownerless group policy + audit queries Admin center + Graph PowerShell Varies
Archival Read-only retire without delete Teams archive + retention Teams admin / Graph / Purview Varies

Licensing reality check. Group naming policy, expiration, and creation restriction each require Entra ID P1 for every member of the governed groups — not just the admin. Access reviews and lifecycle workflows need Entra ID P2 (or the standalone Microsoft Entra ID Governance SKU). Container sensitivity labels are part of Microsoft Purview Information Protection (included in many E3/E5 stacks; confirm yours). Confirm entitlements before you promise any of this to a steering committee — discovering mid-rollout that 2,000 frontline workers lack P1 derails the program and the credibility.

Install the two module families used throughout. The Microsoft Graph PowerShell SDK supersedes the deprecated AzureAD and MSOnline modules; the Exchange/Purview Security & Compliance connection carries the sensitivity-label cmdlets.

# Graph SDK — directory settings, expiration, groups, access reviews
Install-Module Microsoft.Graph -Scope CurrentUser

# Security & Compliance (Purview) PowerShell — sensitivity labels & label policies
Install-Module ExchangeOnlineManagement -Scope CurrentUser

Connect-MgGraph -Scopes @(
    "Directory.ReadWrite.All",       # directory settings (naming, creation)
    "Group.ReadWrite.All",           # group reads/writes, label backfill
    "Policy.ReadWrite.Authorization",# authorization policy (default user role)
    "AccessReview.ReadWrite.All"     # access review definitions
)

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should understand the Microsoft 365 Groups model: a Microsoft 365 Group (formerly “Office 365 Group” / “Unified Group”) is a directory object with groupTypes containing Unified, carrying members and owners, that provisions connected workloads (Exchange mailbox, SharePoint site, Teams, Planner). You should know the difference between a security group (used for access control and as the target of these policies) and a Microsoft 365 Group (the thing being governed), and between assigned membership (static, owner-managed) and dynamic membership (rule-driven by membershipRule). Comfort with running Microsoft Graph PowerShell, reading JSON, and the Microsoft Purview compliance portal is assumed.

This sits in the Microsoft 365 governance and information protection track. It is the collaboration-surface counterpart to Governing SharePoint and OneDrive External Sharing: Tenant vs Site Controls, Sensitivity Labels, and Access Reviews — every team has a SharePoint site, so the two governance models overlap directly at the container label. The labels themselves are the container scope of the labels covered in Sensitivity Labels in Microsoft Purview: Auto-Labeling, Encryption, Co-Authoring, and Container Inheritance. The guest-lifecycle layer leans on identity governance from Building an Access Reviews Program in Entra ID: Recertifying Privileged Roles, Groups, and Guest Access at Scale and Securing B2B Collaboration with Entra External ID: Cross-Tenant Access Settings and Custom Onboarding. The unmanaged-device control on a container label is enforced through the same Conditional Access machinery as Designing Conditional Access at Scale: A Persona-Based Policy Framework with Authentication Context and Filters.

A quick map of who owns what, so the program lands on the right teams:

Layer What lives here Who typically owns it Governance failure it causes if neglected
Directory settings (Entra) Naming, creation restriction Identity / IAM team Naming chaos; unrestricted self-service sprawl
Lifecycle policy (Entra) Expiration, renewal Collaboration / M365 ops Infinite group accumulation; ownerless data
Information protection (Purview) Container sensitivity labels Security / compliance Unclassified regulated data; external oversharing
Identity governance (Entra P2) Access reviews, entitlement, lifecycle workflows Identity governance team Guest accumulation; stale standing access
Teams / SharePoint admin Teams policies, site controls, archival Workplace / collaboration ops Inconsistent retirement; archive vs delete confusion
Audit & reporting Drift detection, usage reports, SIEM SecOps / platform Policy drift goes unnoticed until an audit

Core concepts

Six mental models make every later configuration obvious.

One object, many workloads — govern the group. A Team is a façade over a Microsoft 365 Group. The group object owns membership, owners, the mailbox, the SharePoint site collection, and the lifecycle properties (expirationDateTime, assignedLabels). Teams, Planner, and the rest are connected resources that read from the group. There is deliberately no Teams-specific naming toggle, no Teams-specific creation toggle, no Teams-specific expiration — because those controls live on the group and therefore govern every connected workload simultaneously. Internalize this and you stop hunting for “the Teams setting” that doesn’t exist.

Naming policy is a directory setting, applied at write time. The naming policy lives in the Group.Unified directory setting template (there is no first-class Set-NamingPolicy cmdlet — you instantiate and patch the template). It does two things on creation and rename: stamps a deterministic prefix/suffix onto the group’s displayName and mailNickname (alias), and rejects names whose user-supplied portion contains a blocked word. It is enforced across all creation surfaces — Teams, Outlook, Planner, SharePoint, the Microsoft 365 admin center, Graph API — with one critical exemption: Global Administrators (and a few other high-privilege roles) bypass it entirely, which is why admin-account testing produces false confidence.

Expiration is an owner-driven, activity-aware lifecycle. The Microsoft 365 Groups expiration policy assigns a lifetime in days. As a group nears expiry, the platform emails its owners to renew; separately, any group with recent activity (a Teams message, a SharePoint file edit, an Outlook conversation, a Planner update, a SharePoint visit) is auto-renewed without anyone clicking anything. A group that is neither renewed nor active is soft-deleted — recoverable for 30 days, after which it is permanently gone. The two load-bearing dependencies: expiration needs human owners (ownerless groups get no renewal prompt and silently expire) and it explicitly excludes dynamic groups from the renewal engine.

Container sensitivity labels enforce container behavior, not file encryption. Sensitivity labels have two scopes: items (files and emails — where they can encrypt and watermark) and groups & sites (containers). A container label applied to a group/Team controls the container’s privacy (public vs private), whether guests can be members, whether unmanaged devices can access the connected SharePoint site (full access / web-only / blocked, via Conditional Access), the site’s external sharing scope, and the default sharing link type. A container label does not by itself encrypt the files inside the team — that is the item scope’s job, applied to documents. The same label can carry both scopes, but the container settings and the encryption settings are configured independently.

Guests are governed at two boundaries and re-attested over time. A container label gates guests at the group boundary (can a guest be added to this team at all). The tenant boundary — who may invite, which domains are allowed, what Conditional Access guests face — is governed separately through external collaboration and cross-tenant access settings. And because access granted is access that lingers, the lifecycle of each guest is governed by access reviews: a recurring campaign where owners (or named reviewers) re-attest each external member, and unreviewed or denied guests are auto-removed. Three layers — boundary, posture, lifecycle — that stack.

Soft-delete, hard-delete, and archive are three different retirements. When a team is “deleted” it is soft-deleted (the group goes to the deleted-items container, recoverable for 30 days, all workloads frozen). After 30 days it is hard-deleted (permanent). Archiving a team is different again: the team becomes read-only — members can read history but not post or edit — while the group and its data remain fully intact and instantly un-archivable. Choosing the right retirement (archive a finished-but-referenced project, soft-delete a mistake, let expiration soft-delete dormant ones) is a governance decision, not a technicality.

The vocabulary in one table

Pin down every moving part before the deep sections. The glossary repeats these for lookup; this table is the model side by side:

Concept One-line definition Where it lives Why it matters to governance
Microsoft 365 Group Directory object (groupTypes: Unified) provisioning connected workloads Entra ID The single object all five controls act on
Team The Teams workload layered on a Microsoft 365 Group Connected to the group What users see; not the governance object
Group.Unified setting Directory setting template holding naming + creation config Entra ID directory settings Where naming and creation control physically live
Naming policy Prefix/suffix + blocked words on name/alias Group.Unified values Consistency; admin-exempt gotcha
Expiration policy Lifetime in days + renewal/soft-delete M365 Groups lifecycle policy Sprawl control; needs owners; excludes dynamic
Container label Sensitivity label, group/site scope Purview + group assignedLabels Privacy/guest/device/sharing enforcement
Label policy Publishes labels to users; sets mandatory/default Purview Without it labels never appear on groups
Access review Recurring re-attestation campaign Entra ID Governance (P2) Guest lifecycle; auto-removes stale access
External collaboration Who can invite; allowed/blocked domains Entra external identities Guest invitation boundary
Ownerless group policy Auto-nominates owners for groups with none Microsoft 365 admin center Keeps renewal working; accountability
Soft-delete / hard-delete 30-day recoverable / permanent Deleted items container Recovery window vs permanence
Archive Read-only retire, data intact Teams admin / Graph Retire-without-delete for finished work

The naming policy: prefixes, suffixes, and blocked words

A naming policy is the cheapest, highest-visibility governance win — every new team’s name announces that governance exists. It does exactly two things, and understanding the mechanics prevents the classic rollout bugs.

What the policy actually transforms

The policy operates on two properties: displayName (the friendly name users see) and mailNickname (the email alias, used for the group’s SMTP address and SharePoint URL). The prefix/suffix string is a template made of fixed text and attribute tokens resolved from the creator’s Entra user object. The literal token [GroupName] represents whatever the user typed. A template of GRP_[Department]_[GroupName] typed by a Marketing user who enters “Campaign Planning” produces the display name GRP_Marketing_Campaign Planning and a sanitized alias.

The blocked-words list is a case-insensitive, comma-separated list (up to 5,000 entries, each up to 50 characters) that matches against the user-supplied portion only — not your own prefix. So blocking HR does not break a prefix that happens to contain those letters; it blocks a user from typing a name containing HR as a word fragment (the match is substring-based, so be deliberate — blocking HR also blocks “THREAD”).

The supported attribute tokens, and the behavior when an attribute is empty, are the details people get wrong:

Token Resolves from (creator’s user object) Behavior if attribute is empty Typical use
[GroupName] The name the user typed (mandatory token) N/A — it’s the user input Always include exactly once
[Department] department attribute Token removed; surrounding text remains Departmental grouping
[Company] companyName attribute Token removed Multi-company tenant separation
[Office] physicalDeliveryOfficeName Token removed Site/office prefixing
[StateOrProvince] state Token removed Regional grouping
[CountryOrRegion] country Token removed Geo separation
[Title] jobTitle Token removed Rarely useful; high cardinality
Fixed text (e.g. GRP_) Literal Always present Stable, searchable prefix

The [GroupName] trap. [GroupName] is the literal token for the user’s input. Forget it and every group collapses to the same static string — a GRP_Marketing_ prefix with no user portion means every Marketing group is literally named “GRP_Marketing_”, and creation fails on the second one (duplicate alias). This is the single most common naming-policy rollout bug. Always include [GroupName] exactly once.

Prefix vs suffix, and length limits

You can place tokens before and after [GroupName]. A prefix is more useful for search and sort (everything groups together alphabetically); a suffix (e.g. [GroupName]_EXT for externally-shared teams) reads more naturally to users. The combined result must respect the platform limits — exceed them and creation fails with a length error.

Constraint Limit Consequence of exceeding
displayName total length 256 characters Creation rejected
mailNickname (alias) total length 64 characters Creation rejected
Blocked-words list entries 5,000 Cannot add more
Each blocked word length 50 characters Entry rejected
Prefix + suffix combined fixed text Reasonable (keep < ~50 chars) Eats into user’s available length

Configuring it

There is no first-class cmdlet — instantiate the Group.Unified template from a directory setting, then patch its values. (The cmdlets here use the beta Graph profile because directory-setting templates surface there.)

# Get (or create) the Group.Unified directory setting from its template
$template = Get-MgBetaDirectorySettingTemplate |
    Where-Object DisplayName -eq "Group.Unified"

$setting = Get-MgBetaDirectorySetting |
    Where-Object TemplateId -eq $template.Id

if (-not $setting) {
    $values = $template.Values | ForEach-Object {
        @{ Name = $_.Name; Value = $_.DefaultValue }
    }
    $setting = New-MgBetaDirectorySetting -TemplateId $template.Id -Values $values
}
# Apply the naming convention and the blocked-word list
$body = $setting.Values
($body | Where-Object Name -eq "PrefixSuffixNamingRequirement").Value =
    "GRP_[Department]_[GroupName]"
($body | Where-Object Name -eq "CustomBlockedWordsList").Value =
    "CEO,Payroll,Legal,Board,Confidential,Director,Executive,Finance"

Update-MgBetaDirectorySetting -DirectorySettingId $setting.Id -Values $body

Global Administrators, Partner Tier1/Tier2 Support, User Administrator, and Directory Writers roles are exempt from naming enforcement and blocked words. Always validate the policy by creating a group as a standard, non-admin user — admin testing will sail past the very rules you are trying to verify.

The directory-setting value names you will touch (the ones relevant to governance — the template has more):

Value name (Group.Unified) Type Purpose Example value
PrefixSuffixNamingRequirement String The naming template GRP_[Department]_[GroupName]
CustomBlockedWordsList String (CSV) Blocked words (user portion) CEO,Payroll,Legal
EnableGroupCreation Boolean Whether all users can create false
GroupCreationAllowedGroupId GUID Security group allowed to create <group object id>
AllowGuestsToBeGroupOwner Boolean Can guests own groups false
AllowGuestsToAccessGroups Boolean Can guests access group resources true
GuestUsageGuidelinesUrl String URL shown to guests https://contoso.com/guest-policy
UsageGuidelinesUrl String “Group usage guidelines” link in clients https://contoso.com/teams-policy
EnableMSStandardBlockedWords Boolean Microsoft’s profanity list (no custom edit) true

Expiration and renewal: bounding the lifecycle

Left alone, groups accumulate forever — every meeting, every short project, every experiment leaves a permanent team. The expiration policy is how you put a clock on them.

How the lifecycle actually runs

Set a lifetime in days (the canonical value is 180; the minimum is 30). The platform tracks each group’s expirationDateTime. As that date approaches, two things happen in parallel:

  1. Activity-based auto-renewal. If the group had qualifying activity within the renewal window, its expiration is pushed forward automatically — no human action. Qualifying activity includes: a Teams channel message or visit, a SharePoint file view/edit, an Outlook group-mailbox conversation, a Yammer/Viva Engage post, and a Planner change. In practice this means active teams never expire — only genuinely dormant ones reach the renewal email, which is exactly the signal you want.

  2. Owner renewal notifications. For groups without qualifying activity, the platform emails the group owners at intervals before expiry (typically at 30 days, 15 days, and 1 day out) asking them to renew with one click. Renewing resets the clock by another full lifetime.

A group that is neither active nor renewed by its owners is soft-deleted at expiry — recoverable for 30 days via the deleted-groups container, then permanently removed. The renewal notification intervals and what happens at each:

Time before expiry Platform action Who is notified What clears it
Continuously Activity check (none — automatic) Any qualifying activity auto-renews
30 days First renewal email Group owners Owner clicks “Renew” or activity occurs
15 days Second renewal email Group owners Owner clicks “Renew” or activity occurs
1 day Final renewal email Group owners Owner clicks “Renew” or activity occurs
Expiry Soft-delete Owners notified of deletion Restore within 30 days
Expiry + 30 days Hard-delete (permanent) Unrecoverable

Scope it before you trust it

The policy’s scope (ManagedGroupTypes) is the most consequential setting. Start narrow.

ManagedGroupTypes What it governs When to use Risk
None Nothing (policy effectively off) Disable without deleting the policy None
Selected Only explicitly added groups Pilot — scope to one security group first Low; controlled blast radius
All Every Microsoft 365 Group in the tenant Steady state, after piloting and ownerless cleanup High if owners/dynamic groups not handled
# Pilot: 180-day lifetime, scoped to selected groups, renewal notices to a governance mailbox
Update-MgGroupLifecyclePolicy `
    -GroupLifecyclePolicyId (Get-MgGroupLifecyclePolicy).Id `
    -GroupLifetimeInDays 180 `
    -ManagedGroupTypes "Selected" `
    -AlternateNotificationEmails "groups-governance@contoso.com"
# If no policy exists yet, create it, then add pilot groups to its Selected scope
$policyId = (Get-MgGroupLifecyclePolicy).Id
$pilot    = "11111111-1111-1111-1111-111111111111"
New-MgGroupLifecyclePolicyGroup -GroupLifecyclePolicyId $policyId `
    -AdditionalProperties @{ "groupId" = $pilot }

Ownerless groups never get a renewal prompt and silently expire. This is why the ownerless-group cleanup (covered under drift) is not optional — it is a precondition for ever setting ManagedGroupTypes = All. And dynamic Microsoft 365 Groups are excluded from the renewal engine entirely: a dynamic group with real SharePoint activity will still hit expiry because activity-based renewal does not apply to it, and a SCIM/dynamic group typically has no human owner to renew it. Audit membershipRule and owner count before widening scope, never after the first deletion wave.

The two hard constraints that cause the worst incidents, stated plainly:

Expiration dependency Why it matters What breaks if ignored
At least one human owner Renewal emails go to owners only Ownerless groups expire and soft-delete with no warning to anyone
Assigned (not dynamic) membership Activity-based auto-renewal only applies to assigned groups Active dynamic teams still expire on schedule
Entra ID P1 for all members Licensing requirement Policy may not apply / compliance gap
Communication to owners Owners must know the renewal mechanic Panic tickets about “deleted” teams on the first wave

Restricting who can create teams

By default, any user can create a Microsoft 365 Group (and therefore a Team, a Planner plan, an Outlook group, a SharePoint site). To gate that, set EnableGroupCreation to false and point GroupCreationAllowedGroupId at a security group whose members retain the right. This one setting governs creation across all surfaces simultaneously — there is, again, no Teams-only toggle.

# Restrict creation to members of a 'Team-Creators' security group
$allowed = Get-MgGroup -Filter "displayName eq 'Team-Creators'"

$body = $setting.Values
($body | Where-Object Name -eq "EnableGroupCreation").Value = "false"
($body | Where-Object Name -eq "GroupCreationAllowedGroupId").Value = $allowed.Id

Update-MgBetaDirectorySetting -DirectorySettingId $setting.Id -Values $body

The three creation-control postures

There is no single “right” answer — it is a trade-off between safety and self-service friction. The realistic options:

Posture EnableGroupCreation Who creates Best for Cost
Open self-service true (default) Everyone Tiny/low-risk tenants; max agility Sprawl; no front-door governance
Restricted + request flow false + allowed group A delegated set + a request workflow Most enterprises Build/run a request workflow
Template-driven false + provisioning app A provisioning app/PnP solution Mature orgs wanting consistent teams Significant build investment
Fully locked (IT-only) false, no broad allowed group IT only Highly regulated; low collaboration tempo High friction; shadow-IT risk

Restricting creation does not stop users from needing a team — it stops them creating one ad hoc. Pair it with a request workflow (a Power Automate flow, a ServiceNow/Jira catalog item, or a Teams provisioning app like PnP Provisioning) so legitimate requests are fulfilled in hours, with the right label and owners applied at birth. Governance that only says “no” gets routed around with personal accounts, consumer apps, and shadow IT — the worst possible outcome.

What the restriction does and does not block — a common source of confusion:

Action Blocked by creation restriction? Notes
Create a Team in Teams Yes The “Create team” path is hidden/blocked for non-members
Create an Outlook group Yes Same underlying group creation
Create a Planner plan (new group) Yes Planner backed by a new group is blocked
Create a SharePoint team site (group-connected) Yes Group-connected site creation is blocked
Create a communication SharePoint site No Not group-backed; governed by SharePoint settings
Be added to an existing team No Membership is separate from creation
Create a private/shared channel No Channels live inside an existing team
Self-service via approved request flow No (by design) The flow runs as a privileged account

Container sensitivity labels: privacy, guests, devices, sharing

This is the richest control. A container sensitivity label applied to a Team/group enforces four families of behavior on the container and its connected SharePoint site. Understand each family, then author a small, opinionated set.

The four control families

Control family What it governs Setting(s) Values
Privacy Public vs private group Container privacy Public, Private, or “let user decide”
External (guest) access Whether guests can be members Guest access on the container Allow / Block guest membership
Unmanaged-device access Access from non-compliant devices to the site Conditional Access (via label) Full / Limited web-only / Block
External sharing Site’s external sharing scope + default link SharePoint site sharing Anyone / New+existing guests / Existing guests / Only people in org

The privacy choice on the label closes a real gap: by default users can flip a team between public and private freely. A label can force privacy (e.g. a “Confidential” label forces Private) so a regulated team cannot be made public by an unaware user.

The guest control determines whether the group will accept external members at all. A “Highly Confidential — Internal Only” label that blocks guests means even an owner cannot add an external user — the platform refuses.

The unmanaged-device control routes through Conditional Access: the label sets a session policy so that access from a device that is not Intune-compliant or Entra hybrid-joined is either limited to web-only with no download/print/sync, or blocked entirely. This is how a container label enforces device posture without you authoring a separate CA policy per team.

The external-sharing control sets the connected SharePoint site’s sharing ceiling. SiteExternalSharingControlType accepts these values:

SiteExternalSharingControlType Meaning Use for
ExternalUserAndGuestSharing “Anyone” — anonymous/shareable links allowed Rarely; only deliberately public content
ExternalUserSharingOnly New and existing guests (authenticated) Normal external collaboration
ExistingExternalUserSharingOnly Only guests already in the directory Tightened collaboration
Disabled Only people in the organization Confidential/internal-only containers

Authoring a label

Connect to Purview PowerShell, create the label with the Site, UnifiedGroup content type, and configure container settings via AdvancedSettings plus the dedicated site parameters.

Connect-IPPSSession -UserPrincipalName admin@contoso.com

New-Label -Name "Confidential-Internal" `
    -DisplayName "Confidential - Internal Only" `
    -Tooltip "Private team, no guests, internal sharing, managed devices only" `
    -ContentType "Site, UnifiedGroup"

# Guest and group-creation behaviors
Set-Label -Identity "Confidential-Internal" -AdvancedSettings @{
    BlockGuestUserAccessOnGroupCreation = "true"   # no guests can be added
    AllowEmailFromGuestUsers            = "false"
    AllowAccessToGuestUsers             = "false"
}

# Privacy + SharePoint site sharing posture
Set-Label -Identity "Confidential-Internal" `
    -SiteAndGroupProtectionEnabled $true `
    -SiteExternalSharingControlType "Disabled"

A worked four-label set covering the privacy/guest/device/sharing matrix — the goal is a decision a user makes in two seconds, so keep it to three or four:

Label Privacy Guests Unmanaged devices External sharing Typical content
Public Public Allowed Full access New + existing guests Open, non-sensitive collaboration
General Private (default) Allowed Full access New + existing guests Day-to-day project work
Confidential — Internal Private (forced) Blocked Web-only (no download) Only people in org Regulated/sensitive internal data
Highly Confidential Private (forced) Blocked Blocked Only people in org M&A, legal hold, crown-jewel data

Keep the menu short. A label list of fifteen options causes mislabeling — users pick wrong or pick the default to escape the decision. Three or four labels covering the real matrix is the sweet spot. Long, granular label taxonomies are a classic over-engineering failure that reduces classification accuracy.

The Set-Label advanced settings most relevant to containers (there are more; these are the load-bearing ones):

Advanced setting Effect Values
BlockGuestUserAccessOnGroupCreation Prevent guests being added on creation true / false
AllowAccessToGuestUsers Whether guests can access at all true / false
AllowEmailFromGuestUsers Guests can email the group true / false
MembersCanShare Members may share the site externally MemberShare / Disabled
EnableGroupCreation (within container settings) Whether labeled containers can be created by users true / false

Publishing labels and enforcing them on teams

A label does nothing until a label policy publishes it to users and tenant-level container labeling is switched on. This sequencing trips up most rollouts.

Step 1 — Turn on container labeling at the tenant

Container sensitivity labeling is off by default. Until you enable it, labels will not appear on groups or sites at all, no matter how many you author. Sync labels into Entra and enable the SharePoint integration:

# Sync sensitivity labels into Entra ID so they're usable on containers
Execute-AzureAdLabelSync

# Enable SharePoint/OneDrive to honor sensitivity labels on sites
Set-SPOTenant -EnableAIPIntegration $true

Step 2 — Publish with a label policy (mandatory + default)

A label policy makes the labels visible and can make labeling mandatory at creation and supply a default label for users who would otherwise skip it.

New-LabelPolicy -Name "Container-Label-Policy" `
    -Labels "Public","General","Confidential-Internal","Highly-Confidential" `
    -ExchangeLocation "All"

# Make a label mandatory for groups and set a sensible default
Set-LabelPolicy -Identity "Container-Label-Policy" -AdvancedSettings @{
    DefaultContainerLabel = (Get-Label -Identity "General").Guid
    MandatoryLabelForGroup = "true"
}

The label-policy advanced settings that matter for containers:

Label-policy setting Effect Recommendation
MandatoryLabelForGroup Force a label choice when creating a group/team true in regulated tenants
DefaultContainerLabel Default label applied if user doesn’t choose Set to your safest “General”
DisableMandatoryInOutlook Exempt Outlook from mandatory item labeling Container vs item nuance
Policy scope (users/groups) Who sees these labels Pilot to a group first

Step 3 — Backfill existing teams

Teams created before labeling are unlabeled. Backfill them by patching the group’s assignedLabels via Graph:

$labelId = (Get-Label -Identity "General").Guid
$teams   = Get-MgGroup -Filter "groupTypes/any(c:c eq 'Unified')" -All

foreach ($t in $teams) {
    Update-MgGroup -GroupId $t.Id -AdditionalProperties @{
        assignedLabels = @(@{ labelId = $labelId })
    }
}

Backfill sets the floor going forward — it does not retroactively evict. Two propagation realities: (1) a privacy or guest change on a label can take time to propagate to the connected SharePoint site (not instantaneous), and (2) changing a label on an existing group does not remove guests already added under the old policy. So backfill must be paired with a one-time guest cleanup (the access-review and audit work below). Treat the label change as “from now on,” then clean up the existing state separately.

The propagation and retroactivity behaviors, so expectations are calibrated:

Change Propagates to SharePoint site? Retroactive on existing state? Operational implication
Apply label to existing group Yes (asynchronously) No — existing guests remain Pair with guest cleanup
Change privacy on label Eventually No — doesn’t reshuffle membership Don’t expect instant effect
Change external-sharing on label Eventually Existing shared links may persist Audit existing links separately
Block guests on label Future adds blocked Existing guests stay Run a guest review
Change unmanaged-device control Via CA, near-real-time Applies to next session Sessions re-evaluate

Guest access governance: invitation, posture, and lifecycle

Container labels gate guests at the group boundary. Guests at the tenant boundary, and over time, need three stacked controls.

Layer 1 — External collaboration and cross-tenant access (the invitation boundary)

Decide who may invite guests and which domains are allowed. Most tenants want member-or-admin invitation rights, never “anyone including guests,” and an allow-list (or block-list) of partner domains. The guest-invite settings:

Setting Options Recommended Why
Who can invite guests Anyone / Members & admins / Admins & guest-inviter role / No one Members & admins (or guest-inviter role) Limit invitation sprawl
Guest user access level Same as members / Limited / Restricted Limited or Restricted Guests shouldn’t enumerate the directory
Collaboration domain restrictions Allow specified / Block specified Allow-list partner domains Prevent invites to arbitrary domains
Cross-tenant access (B2B) Per-tenant inbound/outbound trust Configure trusted partner tenants Granular B2B trust, MFA pass-through

These are configured in the Entra admin center under External Identities; cross-tenant access settings let you trust a partner tenant’s MFA and device claims so guests aren’t double-prompted. See Securing B2B Collaboration with Entra External ID: Cross-Tenant Access Settings and Custom Onboarding for the full model.

Layer 2 — Conditional Access for guests (the posture boundary)

Guests authenticate against their home tenant, so you cannot enroll or manage their device — device-compliance Conditional Access doesn’t apply the way it does for employees. Instead, target the All guest and external users user scope with a policy that requires MFA and uses session controls (sign-in frequency, no persistent browser). The realistic guest CA controls:

CA control for guests Works for guests? Use
Require MFA Yes Always — baseline for any guest access
Require compliant device No (can’t manage their device) Use the container-label web-only control instead
Require hybrid-joined device No Same
Sign-in frequency / no persistent browser Yes Reduce standing session risk
Block legacy authentication Yes Always
Terms of use acceptance Yes Compliance/audit trail

Layer 3 — Access reviews (the lifecycle boundary)

This is the control that actually removes stale guests. A recurring access review has owners (or named reviewers) re-attest each external member; with auto-apply and a default of Deny, inaction revokes access. Create one scoped to all Microsoft 365 Groups containing guests:

$params = @{
    displayName          = "Quarterly guest review - all M365 Groups"
    descriptionForAdmins = "Owners re-attest external members each quarter"
    scope = @{
        "@odata.type" = "#microsoft.graph.accessReviewQueryScope"
        query         = "/groups?`$filter=groupTypes/any(c:c eq 'Unified')"
        queryType     = "MicrosoftGraph"
    }
    reviewers = @(@{ query = "./owners"; queryType = "MicrosoftGraph" })
    settings = @{
        recurrence = @{
            pattern = @{ type = "absoluteMonthly"; interval = 3 }
            range   = @{ type = "noEnd"; startDate = "2026-06-01" }
        }
        defaultDecision           = "Deny"     # remove if no decision
        defaultDecisionEnabled    = $true
        autoApplyDecisionsEnabled = $true
        instanceDurationInDays    = 14
    }
}

New-MgIdentityGovernanceAccessReviewDefinition -BodyParameter $params

defaultDecision = "Deny" and autoApplyDecisionsEnabled = $true must be set together, or the review becomes a quarterly box-ticking exercise that removes no one. The entire point of a review is that not responding revokes access. Give owners 14 days, add an escalation/fallback reviewer, and scope reviewers to ./owners so accountability sits with the people who actually know the guests.

The access-review settings that determine whether the review does anything:

Setting Effect Governance-correct value
defaultDecision Decision applied when no one reviews Deny (revoke on inaction)
autoApplyDecisionsEnabled Whether decisions are enforced automatically true
instanceDurationInDays How long reviewers have 14 (balance urgency vs availability)
reviewers Who attests ./owners (+ fallback)
recurrence Cadence Quarterly for guests; monthly for crown jewels
recommendationsEnabled Show usage-based recommendations true (helps reviewers decide)

Detecting drift: ownerless, unlabeled, dormant, orphaned

Governance is only real if you can prove it and catch erosion. Four queries cover the bulk of operational reporting.

Ownerless and under-owned groups

These break renewal and accountability. Every governed group should have at least two owners.

$risky = foreach ($g in Get-MgGroup -Filter "groupTypes/any(c:c eq 'Unified')" -All) {
    $owners = Get-MgGroupOwner -GroupId $g.Id -All
    if ($owners.Count -lt 2) {
        [pscustomobject]@{
            Group  = $g.DisplayName
            Owners = $owners.Count
            Id     = $g.Id
        }
    }
}
$risky | Sort-Object Owners | Export-Csv ./ownerless-groups.csv -NoTypeInformation

Microsoft 365 also ships a built-in ownerless groups policy (Microsoft 365 admin center) that automatically emails the most-active members of an ownerless group asking them to nominate themselves as owners. Enable it so the CSV above trends toward empty. Its key settings:

Ownerless-group policy setting Purpose Recommended
Enable policy Turn on auto-nomination emails Yes
Max active members to email How many candidates get the prompt 2–3
Allowed security group (who’s in scope) Limit which groups the policy targets Scope to governed groups
Number of weeks to send How long to keep prompting 4
Require manager approval Whether a manager must approve the new owner Optional (adds rigor)

Unlabeled groups (label drift)

Find Unified groups still missing a container label after backfill:

Get-MgGroup -Filter "groupTypes/any(c:c eq 'Unified')" -All `
    -Property "id,displayName,assignedLabels" |
    Where-Object { -not $_.AssignedLabels } |
    Select-Object DisplayName, Id

Dormant teams (usage)

Last-activity and message-count data for dormant-team identification comes from the Microsoft 365 usage reports (Teams team activity, Groups activity) in the admin center or via the reports Graph endpoints. Reconcile dormant teams against expiration outcomes — a team that’s dormant but kept getting auto-renewed by a stray SharePoint visit is a candidate for manual archival or deletion.

Orphaned guests

Guests on teams that should have none (per their label), or guests whose inviting project is long finished. The access review removes them on cadence; an ad-hoc query finds them between reviews:

# Guests that are members of any Unified group (feed into review/cleanup)
$guests = Get-MgUser -Filter "userType eq 'Guest'" -All
foreach ($u in $guests) {
    Get-MgUserMemberOf -UserId $u.Id -All |
      Where-Object { $_.AdditionalProperties.groupTypes -contains "Unified" } |
      ForEach-Object {
        [pscustomobject]@{ Guest = $u.Mail; Group = $_.AdditionalProperties.displayName }
      }
}

The drift signals and how to remediate each:

Drift signal Detect with Remediate with Cadence
Ownerless / under-owned Owner-count query Ownerless-group policy; assign owners Weekly
Unlabeled group assignedLabels empty query Backfill default label Weekly until zero
Dormant team Teams/Groups usage reports Archive or delete; let expiration act Monthly
Orphaned guest Guest membership query Access review auto-remove Quarterly (review)
Public team holding sensitive data Privacy + label mismatch query Re-label; force private Monthly
Duplicate-named teams displayName grouping Merge/consolidate; delete dupes Quarterly

Archival and retirement: archive vs soft-delete vs hard-delete

Retirement is a governance decision with three distinct mechanisms — choosing wrong either loses data or clutters the tenant.

Archive when a team’s work is finished but still referenced (a completed project people occasionally search). Archiving makes the team read-only — members read history but can’t post or edit — while the group, SharePoint site, files, and channels stay fully intact and the team can be un-archived instantly. You can also set the SharePoint site to read-only at the same time.

# Archive a team (read-only); set SharePoint site read-only too
$teamId = (Get-MgGroup -Filter "displayName eq 'GRP_Eng_Project Phoenix'").Id
Invoke-MgArchiveTeam -TeamId $teamId `
    -BodyParameter @{ shouldSetSpoSiteReadOnlyForMembers = $true }

Soft-delete when a team was a mistake or is genuinely no longer needed but you want a safety window — it’s recoverable for 30 days. Expiration produces soft-deletes automatically.

Hard-delete is what happens after the 30-day window, or via permanent removal of an already-soft-deleted group — unrecoverable. Restore within the window with Graph (the UI has no bulk path):

# Restore soft-deleted groups (within 30 days) matching a naming pattern
Get-MgDirectoryDeletedItemAsGroup -All |
  Where-Object { $_.GroupTypes -contains "Unified" -and $_.DisplayName -like "GRP_Plant_*" } |
  ForEach-Object { Restore-MgDirectoryDeletedItem -DirectoryObjectId $_.Id }

The retirement decision matrix:

You want to… Mechanism Data state Reversible? Who initiates
Retire finished-but-referenced work Archive Read-only, fully intact Instantly (un-archive) Owner / admin
Retire a mistake with a safety net Soft-delete Frozen in deleted-items 30 days Owner / admin / expiration
Permanently remove Hard-delete Gone No Admin / 30-day timeout
Preserve for compliance/legal Retention/hold (Purview) Preserved regardless Per retention policy Compliance
Reduce noise without deleting Hide from Teams / leave Intact, hidden from rail Yes User

Retention and legal hold (Microsoft Purview) override deletion: a group under a retention policy or eDiscovery hold won’t truly purge even when soft-deleted past 30 days — the content is preserved in place. This is the right behavior for regulated data but surprises admins who “deleted” a team and find its SharePoint content still discoverable. See Microsoft Purview Records Management: Retention Labels, Auto-Apply, Disposition Review, and Event-Based Holds for how retention interacts with the group lifecycle.

Sensitivity labels vs classic group classification

Before container sensitivity labels existed, Microsoft 365 Groups had classic classification — a flat list of free-text labels (Low, Medium, High Business Impact) set via the same Group.Unified directory setting (ClassificationList). It still works, but it is a label without teeth: it tags the group with a string and nothing enforces anything. Container sensitivity labels supersede it by binding the label to actual enforcement (privacy, guests, devices, sharing). The two should not coexist in steady state.

Dimension Classic classification Container sensitivity label
Configured in Group.Unified ClassificationList Microsoft Purview
Enforces privacy No (string only) Yes (can force Private)
Controls guest access No Yes (block/allow)
Controls unmanaged devices No Yes (via Conditional Access)
Controls external sharing No Yes (site sharing scope)
Encrypts files No Yes (item scope of same label)
Visible in Teams/SharePoint UI Yes (as text) Yes (as label, enforced)
License Entra ID P1 Purview Information Protection
Recommended today No — migrate off Yes

Do not run both. If you previously set ClassificationList, plan a migration: map each classic class to a container label, backfill, then clear the classification list so users see one taxonomy that actually enforces. Two parallel labeling schemes confuse users and split your reporting.

Architecture at a glance

Picture the whole governance control plane as a set of lenses focused on a single object at the center — the Microsoft 365 Group. Everything radiates from that object because every Team, mailbox, SharePoint site, Planner plan, and guest membership is a property of, or a workload connected to, that one group. There is no separate “Teams object” to govern; there is the group, and Teams is one face of it.

Trace a team’s life left to right through the control plane. At birth, two Entra ID directory settings intercept creation: the creation restriction (Group.UnifiedEnableGroupCreation = false + an allowed security group) decides whether this user may create at all, and the naming policy (PrefixSuffixNamingRequirement + CustomBlockedWordsList) stamps the name and alias and rejects blocked words. If a label policy makes labeling mandatory, the user must also choose a container sensitivity label at this moment — and that single choice cascades into the connected SharePoint site as privacy (public/private), guest posture (allowed/blocked), unmanaged-device access (full / web-only / blocked, enforced through Conditional Access), and external sharing scope (DisabledExternalUserAndGuestSharing). One object, four enforced behaviors, set at birth from one label.

Through the team’s life, two more lenses operate continuously. The expiration policy (a lifetime in days on the group’s expirationDateTime) watches for activity: active teams auto-renew invisibly, dormant ones email their owners to renew, and the unrenewed are soft-deleted with a 30-day recovery window — which is why the policy depends on human owners and excludes dynamic groups. In parallel, guest governance stacks three controls on the same group: the invitation boundary (external collaboration / cross-tenant access), the posture boundary (Conditional Access requiring MFA for All guest and external users), and the lifecycle boundary (a recurring access review where owners re-attest each guest and inaction auto-revokes).

Finally, a drift-and-audit layer reads the object’s state — owner count, assignedLabels, last-activity from usage reports, guest membership — and feeds remediation: the ownerless-group policy nominates new owners, the label backfill closes classification gaps, and dormant teams are routed to archive (read-only, intact), soft-delete (recoverable), or hard-delete (permanent). The convergence point of the entire design is the same in every path: the control you want lives on the Microsoft 365 Group, not on “Teams.” Localize a governance need to a property of that object and you immediately know which directory setting, which label, or which policy configures it.

Real-world scenario

Nordhaven Manufacturing runs a 40,000-seat Microsoft 365 tenant: roughly 11,000 Microsoft 365 Groups after four years of open self-service Teams, heavy external collaboration with a supplier network across 60+ partner domains, and a regulated-data footprint (product designs, contracts, some PII) under ISO 27001 and customer-mandated controls. The collaboration ops team is six people; the identity team is four. An external audit flagged three findings: unclassified data in externally-shared teams, guests with multi-year standing access, and “no demonstrable group lifecycle.” Leadership gave them one quarter to remediate.

Under pressure, they made the classic mistake: they treated the findings as three independent fixes and rolled them all out the same week. They flipped expiration to ManagedGroupTypes = "All" with a 180-day lifetime tenant-wide, published a mandatory Confidential-Internal container label, and turned on the creation gate — all at once, with minimal communication.

Six months later, the consequences arrived in a single night. About 600 teams expired and soft-deleted simultaneously — including a cluster of plant-floor and supplier-coordination teams that had real, current SharePoint activity. Activity-based auto-renewal should have saved them, but it never fired: those teams had been provisioned by a SCIM connector into dynamic Microsoft 365 Groups, and dynamic groups are excluded from the renewal engine. Worse, their membership was rule-driven with no human owner, so no renewal email went anywhere. No owner, no dynamic-group renewal, no prompt — just deletion. The plant floor lost access to current work instructions on a Monday morning; the help desk took 300 tickets before 10am.

The breakthrough was recognizing this as one object’s lifecycle behaving exactly as designed against a membership model it doesn’t support. The fix had two parts. That night: recover inside the 30-day window with Graph rather than the UI (which has no bulk restore path) — Get-MgDirectoryDeletedItemAsGroup filtered to the GRP_Plant_* naming pattern, piped to Restore-MgDirectoryDeletedItem. All 600 came back in twenty minutes. The following week: stop trusting expiration to police dynamic groups. They moved every dynamic and SCIM-fed team out of the lifecycle scope (ManagedGroupTypes = "Selected", excluding those IDs) and governed those groups’ lifecycle through access reviews and the ownerless-group policy instead, while keeping expiration for the assigned-membership, owner-backed teams where it actually works.

The remediation then proceeded in the right order: creation gate first (with a ServiceNow request catalog so plant managers got teams in hours), then naming, then container labels with a backfill-plus-guest-cleanup, then expiration scoped only to owner-backed assigned groups, then quarterly guest access reviews with auto-apply and default Deny. The first guest review removed 1,400 stale external members — supplier contractors from finished projects. The audit findings closed. The durable lesson, written on the team’s wall: “Expiration is an owner-driven control. It only works where human owners and assigned membership exist. Audit membershipRule and owner count before widening scope — never after the first deletion wave.”

The incident as a timeline, because the order is the lesson:

Time Event Action taken Effect What it should have been
Week 0 Audit findings Roll out all three controls at once, tenant-wide Looks done Pilot each on a scoped group first
Month 6, 02:00 600 teams soft-delete overnight (automatic expiration) Plant floor loses access Scope expiration to owner-backed assigned groups only
Month 6, 08:00 300 help-desk tickets Diagnose: dynamic groups, no owners, no renewal Root cause found Audit membershipRule + owners before All
Month 6, 08:20 Recover Get-MgDirectoryDeletedItemAsGroupRestore-MgDirectoryDeletedItem All restored in 20 min (correct emergency move)
Month 6, +1 week Re-scope ManagedGroupTypes=Selected, exclude dynamic/SCIM IDs Expiration safe The actual fix
Month 6, +2 weeks Sequence properly Creation gate → naming → labels → expiration → guest reviews Findings closing The right rollout order
Month 7 First guest review Auto-apply, default Deny 1,400 stale guests removed The lifecycle control doing its job

Advantages and disadvantages

Governing the Microsoft 365 Group as the single object both enables this whole control plane and creates the failure modes you must respect:

Advantages (why governing the group works) Disadvantages / risks (why it bites)
One object governs all workloads — naming/expiration/labels/creation apply to Teams, SharePoint, Outlook, Planner at once The same coupling means a misconfigured control (e.g. expiration on dynamic groups) has wide blast radius
Container labels enforce privacy/guest/device/sharing from a single user choice at creation Label changes propagate asynchronously and never retroactively evict existing guests/links
Expiration auto-renews active teams — only genuinely dormant ones need human attention Expiration is owner-driven and excludes dynamic groups — silent deletion where owners/assigned membership are missing
Access reviews make inaction revoke access — guests are re-attested, not accumulated Without defaultDecision=Deny+auto-apply, a review removes no one — a false sense of control
Naming/creation restriction govern every creation surface with one directory setting Global Admins are exempt from naming/creation — admin testing produces false confidence
Native, built-in tooling (no third-party product) — Entra, Purview, Graph Spread across four admin surfaces and two license tiers; requires cross-team coordination
Soft-delete + 30-day recovery + archive give graceful, reversible retirement Retention/legal hold override deletion — “deleted” data can persist, surprising admins

The model is right for any organization that adopted Teams (i.e. all of them) and needs collaboration to stay safe and legible at scale — it is the only approach that scales by policy rather than manual cleanup. It bites hardest where membership is dynamic/SCIM-fed (expiration breaks), where external collaboration is heavy (guest sprawl dominates and labels must be tight), and where teams roll out all controls at once without piloting — every disadvantage above is manageable, but only if you know it exists, which is the entire point of sequencing the rollout.

Hands-on lab

Stand up the core governance controls on a pilot scope, verify each as a non-admin would experience it, and tear down. Run in Microsoft Graph PowerShell + Purview PowerShell. This uses a Selected scope and a pilot security group throughout — nothing tenant-wide — so it is safe to run in a test/dev tenant.

Step 1 — Connect and create a pilot security group.

Connect-MgGraph -Scopes "Directory.ReadWrite.All","Group.ReadWrite.All","AccessReview.ReadWrite.All"

# A security group to scope creation rights AND a separate one to scope expiration
$creators = New-MgGroup -DisplayName "Team-Creators" -MailEnabled:$false `
    -SecurityEnabled:$true -MailNickname "team-creators"

Expected: a group object with an Id. Note it.

Step 2 — Instantiate Group.Unified and apply a naming policy.

$template = Get-MgBetaDirectorySettingTemplate | Where-Object DisplayName -eq "Group.Unified"
$setting  = Get-MgBetaDirectorySetting | Where-Object TemplateId -eq $template.Id
if (-not $setting) {
    $values = $template.Values | ForEach-Object { @{ Name=$_.Name; Value=$_.DefaultValue } }
    $setting = New-MgBetaDirectorySetting -TemplateId $template.Id -Values $values
}
$body = $setting.Values
($body | Where-Object Name -eq "PrefixSuffixNamingRequirement").Value = "GRP_[Department]_[GroupName]"
($body | Where-Object Name -eq "CustomBlockedWordsList").Value = "Payroll,CEO,Board"
Update-MgBetaDirectorySetting -DirectorySettingId $setting.Id -Values $body

Expected: no error. The setting now carries your naming template.

Step 3 — Restrict creation to the pilot group.

$body = (Get-MgBetaDirectorySetting | Where-Object TemplateId -eq $template.Id).Values
($body | Where-Object Name -eq "EnableGroupCreation").Value = "false"
($body | Where-Object Name -eq "GroupCreationAllowedGroupId").Value = $creators.Id
Update-MgBetaDirectorySetting -DirectorySettingId $setting.Id -Values $body

Expected: creation is now gated to Team-Creators members.

Step 4 — Configure an expiration policy scoped to Selected.

$existing = Get-MgGroupLifecyclePolicy
if (-not $existing) {
    New-MgGroupLifecyclePolicy -GroupLifetimeInDays 180 -ManagedGroupTypes "Selected" `
        -AlternateNotificationEmails "groups-governance@contoso.com"
} else {
    Update-MgGroupLifecyclePolicy -GroupLifecyclePolicyId $existing.Id `
        -GroupLifetimeInDays 180 -ManagedGroupTypes "Selected" `
        -AlternateNotificationEmails "groups-governance@contoso.com"
}

Expected: a lifecycle policy with GroupLifetimeInDays = 180, ManagedGroupTypes = Selected.

Step 5 — Author and publish a container sensitivity label (Purview).

Connect-IPPSSession -UserPrincipalName admin@contoso.com
Execute-AzureAdLabelSync
New-Label -Name "Pilot-Confidential" -DisplayName "Pilot - Confidential" `
    -Tooltip "Private, no guests, internal sharing" -ContentType "Site, UnifiedGroup"
Set-Label -Identity "Pilot-Confidential" -SiteAndGroupProtectionEnabled $true `
    -SiteExternalSharingControlType "Disabled" `
    -AdvancedSettings @{ BlockGuestUserAccessOnGroupCreation="true" }
New-LabelPolicy -Name "Pilot-Label-Policy" -Labels "Pilot-Confidential" -ExchangeLocation "All"

Expected: the label exists with ContentType including UnifiedGroup, and a policy publishes it.

Step 6 — Create a quarterly guest access review scoped to Unified groups.

$params = @{
    displayName = "Pilot guest review"
    scope = @{ "@odata.type"="#microsoft.graph.accessReviewQueryScope"
        query="/groups?`$filter=groupTypes/any(c:c eq 'Unified')"; queryType="MicrosoftGraph" }
    reviewers = @(@{ query="./owners"; queryType="MicrosoftGraph" })
    settings = @{
        recurrence = @{ pattern=@{ type="absoluteMonthly"; interval=3 }
            range=@{ type="noEnd"; startDate="2026-06-01" } }
        defaultDecision="Deny"; defaultDecisionEnabled=$true
        autoApplyDecisionsEnabled=$true; instanceDurationInDays=14
    }
}
New-MgIdentityGovernanceAccessReviewDefinition -BodyParameter $params

Expected: a review definition returns with a Status of NotStarted/InProgress.

Validation checklist. Each step maps to a control you can prove:

Step What you configured How to verify (as the right principal)
2 Naming policy As a non-admin in Team-Creators, create “test” → expect GRP_<dept>_test; try a name with “Payroll” → expect rejection
3 Creation restriction Sign in as a user not in Team-Creators → “Create team” is blocked; a member can still create
4 Expiration Add a pilot group to the policy, then Get-MgGroup -GroupId <id> -Property expirationDateTime is populated
5 Container label Create a team → the label picker appears; pick the label → assignedLabels set; try to add a guest → blocked
6 Access review Get-MgIdentityGovernanceAccessReviewDefinition shows it active, reviewers = owners

Verify naming as a non-admin (the critical test):

# Run AS A STANDARD USER, not Global Admin (admins are exempt)
New-MgGroup -DisplayName "test" -GroupTypes "Unified" -MailEnabled:$true `
    -MailNickname "test123" -SecurityEnabled:$false
# Expect the created group's displayName to be GRP_<your-dept>_test

Teardown.

# Re-open creation, clear naming, scope expiration to None, remove pilot artifacts
$body = (Get-MgBetaDirectorySetting | Where-Object TemplateId -eq $template.Id).Values
($body | Where-Object Name -eq "EnableGroupCreation").Value = "true"
($body | Where-Object Name -eq "PrefixSuffixNamingRequirement").Value = ""
($body | Where-Object Name -eq "CustomBlockedWordsList").Value = ""
Update-MgBetaDirectorySetting -DirectorySettingId $setting.Id -Values $body
Update-MgGroupLifecyclePolicy -GroupLifecyclePolicyId (Get-MgGroupLifecyclePolicy).Id -ManagedGroupTypes "None"
Remove-MgGroup -GroupId $creators.Id
Remove-LabelPolicy -Identity "Pilot-Label-Policy" -Confirm:$false
Remove-Label -Identity "Pilot-Confidential" -Confirm:$false

Cost note. Everything here is configuration on licenses you already pay for (Entra ID P1/P2, Purview) — there is no per-resource compute charge. The only “cost” is the license floor, which the lab assumes you have in a test tenant.

Common mistakes & troubleshooting

The recurring failures, as a scannable table you keep open during the rollout, then expanded for the ones that bite hardest.

# Symptom Root cause Confirm (exact cmd / portal path) Fix
1 Every new group has the same name; creation fails on the second [GroupName] token omitted from naming template Get-MgBetaDirectorySetting → inspect PrefixSuffixNamingRequirement Add [GroupName] exactly once
2 Naming policy “isn’t working” when admin tests it Global Admin is exempt from naming/creation Test as a non-admin user Validate with a standard account, always
3 600 teams expired overnight despite activity Dynamic groups excluded from renewal; no owners Check membershipRule populated + Get-MgGroupOwner count Scope expiration to assigned, owner-backed groups; govern dynamic via reviews
4 Sensitivity labels don’t appear on teams/sites Container labeling not enabled at tenant Get-SPOTenantEnableAIPIntegration; was Execute-AzureAdLabelSync run? Set-SPOTenant -EnableAIPIntegration $true; Execute-AzureAdLabelSync
5 Label applied but guests still in the team Label changes don’t retroactively evict Compare assignedLabels vs Get-MgGroupMember guests Run a one-time guest cleanup / access review
6 Access review runs but removes no one defaultDecision not Deny or auto-apply off Get-MgIdentityGovernanceAccessReviewDefinition → settings Set defaultDecision=Deny + autoApplyDecisionsEnabled=$true
7 Owners never see renewal emails Group is ownerless (or notifications to wrong address) Get-MgGroupOwner; check AlternateNotificationEmails Enable ownerless-group policy; set alternate emails
8 Creation restricted but users still make “sites” Communication SharePoint sites aren’t group-backed SharePoint admin → site creation settings Govern SharePoint site creation separately
9 Users bypass the creation gate via personal accounts “No” with no request path → shadow IT Audit for external/personal collaboration Pair restriction with a request workflow
10 Blocked word blocks legitimate names Substring match (e.g. “HR” blocks “THREAD”) Inspect CustomBlockedWordsList Choose words deliberately; test edge cases
11 Two labeling schemes confuse users Classic ClassificationList + container labels both set Get-MgBetaDirectorySettingClassificationList Migrate to labels; clear classification list
12 “Deleted” team’s data still discoverable Retention/legal hold overrides deletion Purview → retention policies / eDiscovery holds Expected — release hold if truly removing
13 Guest CA policy “requires compliant device” never works Can’t manage guests’ devices CA policy targeting guests with device-compliance grant Require MFA + session controls; use label web-only control
14 Expiration set but expirationDateTime null on groups Group not in Selected scope (or None) Get-MgGroup -Property expirationDateTime Add group to lifecycle policy scope

The expanded reasoning for the worst offenders:

1. Every new group collapses to the same name. Root cause: the [GroupName] token is missing from PrefixSuffixNamingRequirement, so the template has no slot for user input — every group is named the static prefix and the second creation fails on a duplicate alias. Confirm: read the setting value. Fix: ensure [GroupName] appears exactly once.

3. Mass overnight expiration despite real activity. Root cause: the teams are dynamic Microsoft 365 Groups (membership rule-driven), which are excluded from activity-based renewal, and being rule-driven they often have no human owner to receive a renewal prompt — so they expire silently even with current SharePoint activity. Confirm: membershipRule is populated and Get-MgGroupOwner returns zero. Fix: move dynamic/SCIM groups out of ManagedGroupTypes and govern their lifecycle through access reviews and the ownerless-group policy; keep expiration for assigned, owner-backed groups.

4. Labels invisible on teams. Root cause: container labeling is off at the tenant — labels exist in Purview but were never synced into Entra (Execute-AzureAdLabelSync) and/or SharePoint integration is disabled (EnableAIPIntegration). Confirm: Get-SPOTenant shows EnableAIPIntegration false. Fix: run the sync and enable the integration; allow propagation time.

6. Reviews that remove nobody. Root cause: the review’s defaultDecision is None/Approve or autoApplyDecisionsEnabled is false, so when reviewers don’t respond, nothing happens — the review is theater. Confirm: inspect the definition settings. Fix: defaultDecision = Deny and autoApplyDecisionsEnabled = $true together, with a fallback reviewer so one unresponsive owner doesn’t strand the campaign.

9. Users routing around the creation gate. Root cause: governance that only blocks, with no fast path to a legitimate team, pushes people to personal OneDrive, consumer chat, or email — strictly worse than a governed team. Confirm: rising external/personal-account collaboration in audit logs. Fix: pair every restriction with a self-service request workflow that delivers a correctly-labeled, owner-assigned team in hours.

Best practices

Security notes

The security controls and what each prevents:

Control Mechanism Prevents Also enables
Container label (force private, block guests) Purview label on group Sensitive data going public / to guests Consistent classification
Container label (web-only unmanaged) Label → Conditional Access session Download/exfil from unmanaged devices BYOD-safe access
External sharing scope Disabled Site sharing control on label External oversharing of confidential sites Internal-only collaboration
Guest invitation restriction External collaboration settings Uncontrolled guest sprawl Allow-listed partner collaboration
Conditional Access for guests CA All guest/external + MFA Unauthenticated/weak guest access Trusted-tenant MFA pass-through
Access review (Deny + auto-apply) Entra ID Governance Standing stale guest access Auditable re-attestation
Least-privilege admin roles Groups Admin / custom roles Over-broad governance admin rights Separation of duties

Cost & sizing

Governance here is licensing, not compute — there is no per-team resource bill. What drives cost is the license floor and the operational effort.

The license/effort drivers:

Driver What it covers Cost basis Watch-out
Entra ID P1 Naming, expiration, creation restriction Per member (governed) Frontline SKUs may lack it
Entra ID P2 / Governance Access reviews, lifecycle workflows Per member (reviewed) Required for the guest lifecycle control
Purview Information Protection Container sensitivity labels Per E3/E5 entitlement Confirm it’s in your SKU
Request workflow Power Automate / ServiceNow build Engineering time + connector licensing Ongoing maintenance
Drift automation Scheduled Graph runbooks + SIEM Engineering time Keep credentials least-privilege
SharePoint storage (indirect) Sprawl footprint Per-GB above quota Expiration/archival reduces it

Interview & exam questions

1. Why is “governing Teams” really “governing Microsoft 365 Groups”? Every Team is layered on a Microsoft 365 Group that owns the membership, mailbox, SharePoint site, and lifecycle properties. Naming, expiration, creation restriction, and labels all live on the group, so they govern Teams and every other connected workload (SharePoint, Outlook, Planner) simultaneously — there is deliberately no Teams-specific toggle for any of them.

2. Where does a group naming policy live and what are its two functions? In the Group.Unified directory setting template (no first-class cmdlet — you patch the template’s PrefixSuffixNamingRequirement and CustomBlockedWordsList). It stamps a deterministic prefix/suffix (fixed text + attribute tokens like [Department], plus the literal [GroupName] for user input) onto the display name and alias, and rejects names whose user-supplied portion contains a blocked word.

3. Why might a naming policy appear not to work when an admin tests it? Global Administrators (and a few other high-privilege roles) are exempt from naming and creation enforcement. Admin-account testing bypasses the very rules being verified, producing false confidence — always validate as a standard, non-admin user.

4. Explain the Microsoft 365 Groups expiration renewal mechanics and their two hard dependencies. A lifetime (days) is set; active groups auto-renew on qualifying activity (Teams/SharePoint/Outlook/Planner), dormant ones email owners to renew, and the unrenewed are soft-deleted (recoverable 30 days). The two dependencies: it needs human owners (ownerless groups get no prompt and silently expire) and it excludes dynamic groups from the renewal engine (a dynamic group expires even with activity).

5. What does a container sensitivity label control, and what does it not control? It controls container behavior: privacy (public/private), guest membership (allow/block), unmanaged-device access (full/web-only/blocked via Conditional Access), and the connected SharePoint site’s external-sharing scope and default link. It does not by itself encrypt the files inside the team — that’s the item scope of a label, applied to documents.

6. A user reports labels don’t appear when creating a team. What’s the most likely cause? Container labeling isn’t enabled at the tenant — the labels were never synced into Entra (Execute-AzureAdLabelSync) and/or SharePoint label integration is off (Set-SPOTenant -EnableAIPIntegration $true). Until both are on, labels don’t surface on groups/sites regardless of how many exist in Purview.

7. You applied a “no guests” label to an existing team but the guests are still there. Why? Label changes are not retroactive — applying or changing a container label blocks future guest additions but does not evict guests already present, and changes propagate to the SharePoint site asynchronously. Backfill sets the floor going forward; remove existing guests with a one-time cleanup or an access review.

8. How do you make an access review actually remove stale guests instead of being theater? Set defaultDecision = "Deny" and autoApplyDecisionsEnabled = $true together, so that inaction by reviewers auto-revokes access and the decision is enforced automatically. Add a fallback reviewer and a bounded duration (e.g. 14 days) so one unresponsive owner doesn’t strand the campaign.

9. Why can’t you require a compliant device for guests in Conditional Access, and what do you do instead? Guests authenticate in their home tenant, so you cannot enroll or manage their device — device-compliance grants don’t apply. Require MFA and use session controls (sign-in frequency, no persistent browser), and enforce unmanaged-device posture through the container label’s web-only control rather than a device-compliance grant.

10. Compare container sensitivity labels with classic group classification. Classic classification (ClassificationList in Group.Unified) is a free-text string that enforces nothing. Container sensitivity labels bind the label to real enforcement — privacy, guest, device, and sharing controls. Labels supersede classification; don’t run both (it splits the taxonomy and confuses users) — migrate to labels and clear the classification list.

11. What’s the difference between archiving, soft-deleting, and hard-deleting a team? Archive makes the team read-only with all data intact and instantly reversible (for finished-but-referenced work). Soft-delete moves it to the deleted-items container, recoverable for 30 days (a safety window; expiration produces these automatically). Hard-delete is permanent (after 30 days or explicit purge). Retention/legal hold overrides deletion — held content persists regardless.

12. In what order should you roll out the five controls, and why? Creation gate → naming → container labels → expiration → guest reviews, piloting each on a scoped group first. They are one system that interacts: expiration without owners orphans data; labels without a creation gate get bypassed by self-service; guest reviews without auto-apply remove no one. Rolling them out simultaneously and untested is how mass deletions and audit failures happen.

These map to MS-102 (Microsoft 365 Administrator) — manage Microsoft 365 Groups, governance, and information protection — and to identity-governance objectives in SC-300 (Identity and Access Administrator) — access reviews, entitlement management, external identities. Container labels and DLP touch SC-400 (Information Protection Administrator). A compact mapping:

Question theme Primary cert Objective area
Groups lifecycle, naming, expiration MS-102 Manage M365 Groups & governance
Container sensitivity labels SC-400 / MS-102 Implement information protection
Access reviews, guest lifecycle SC-300 Plan & implement identity governance
External collaboration, B2B SC-300 Manage external identities
Conditional Access for guests SC-300 Implement Conditional Access
Archival, retention interplay MS-102 / SC-400 Records management & retention

Quick check

  1. A team holding M&A documents was made public by an unaware user. Which single control would have forced it private at creation, and where is it configured?
  2. 600 dynamic, SCIM-fed teams with current SharePoint activity expired and soft-deleted overnight despite an expiration policy. Name the two reasons activity-based renewal didn’t save them.
  3. You published three sensitivity labels but none appear when users create teams. What two tenant-level actions did you most likely skip?
  4. A quarterly guest access review has run twice and removed zero guests. What two settings make a review actually revoke access?
  5. True or false: changing a container label to “block guests” immediately removes the guests already in the team.

Answers

  1. A container sensitivity label that forces Private privacy — configured in Microsoft Purview (Information Protection) and published via a label policy that makes labeling mandatory at creation. A label can force privacy so a regulated team cannot be made public by an unaware user.
  2. (a) Dynamic groups are excluded from the activity-based renewal engine — activity doesn’t auto-renew them. (b) Being rule-driven/SCIM-fed, they typically have no human owner, so no renewal email is sent to anyone. No renewal + no owner = silent expiration. Fix by scoping expiration to assigned, owner-backed groups and governing dynamic groups via access reviews.
  3. You skipped enabling container labeling at the tenant: syncing labels into Entra (Execute-AzureAdLabelSync) and enabling SharePoint label integration (Set-SPOTenant -EnableAIPIntegration $true). Until both are on, labels don’t surface on groups/sites.
  4. defaultDecision = "Deny" (so inaction revokes) and autoApplyDecisionsEnabled = $true (so decisions are enforced automatically). Without both, the review removes no one.
  5. False. Label changes are not retroactive — they block future guest additions but leave existing guests in place. Remove them with a one-time guest cleanup or an access review.

Glossary

Next steps

You can now govern the Microsoft 365 Group as the single object beneath every Team — naming, expiration, creation, labels, and guest lifecycle. Build outward:

TeamsGovernanceSensitivity LabelsMicrosoft 365 GroupsEntra IDLifecycleAccess ReviewsPowerShell
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading