LearnMicrosoft Teams › 2 · Governance & the policy model

The policy assignment engine

Knowing what a policy does is half the job; knowing which policy a user actually HAS is the half that closes tickets. Three assignment routes, one precedence rule, and propagation lag that fools everyone.

The three routes into a user

  1. Direct assignmentGrant-CsTeamsMeetingPolicy -Identity user -PolicyName X. Sticks until explicitly removed. Highest precedence, no exceptions.
  2. Group assignment — policy attached to an Entra group with a rank. A user in several policy-bearing groups gets the policy from the lowest-rank (=highest priority) group. Membership changes flow through automatically — this is the scalable route.
  3. Global (Org-wide default) — what's left when nothing above applies.

Precedence is absolute, not additive: direct beats group beats Global, and the winning policy supplies EVERY setting. There is no per-setting merge — a common and expensive misunderstanding ("we changed Global, why didn't anyone get it?" — because everyone has direct assignments from a 2022 migration script).

The engine's sharp edges

  • Propagation is not instant. Direct grants usually land in minutes; group assignment adds membership-evaluation time; a full org-wide change can take hours to reach every client. The client also caches — sign-out/in forces a re-fetch.
  • An empty direct assignment is still an assignment. Grant ... -PolicyName $null REMOVES the direct route (falls back to group/Global); assigning the policy that merely matches Global still pins the user forever.
  • Batch assignment (New-CsBatchPolicyAssignmentOperation) is fire-and-forget with an operation id — completion is not success; read the per-user errors.
  • Group assignment doesn't cover everything — a few policy types remain direct/Global only; check per type before designing a group-based model.

Design pattern that survives audits

Global = the safe default for everyone. Groups = the exceptions, named for intent (pol-teams-recording-allowed), ranks documented. Direct = break-glass only, reviewed quarterly. Anything else decays into archaeology.

What to watch (proofs)

  • The verdict for one user: Get-CsUserPolicyAssignment -Identity <upn> — shows each policy type, the winning policy, and the ROUTE (Direct/Group <id>) — this single cmdlet is the ticket-closer.
  • Group model inventory: Get-CsGroupPolicyAssignment — every group-attached policy with rank; two groups same rank + same type = order you didn't choose.
  • Batch results: Get-CsBatchPolicyAssignmentOperation -OperationId <id> — read UserState per user; the failures hide here.
  • Drift over time: our scan snapshots every policy instance nightly — when the transcription verdicts said "7 of 11 policies", that census is this engine's output.

PowerShell for this concept

Discussion

No messages yet — start the thread.

Sign in with your email to join the discussion — we send a one-time link, no password.