The lineages under one name
MicrosoftTeams bundles Graph-backed cmdlets (Get-Team family — team/
channel/member objects) and the policy/voice engine descended from Skype
tooling (Get-Cs* — the ~140 policy types serv365 scans). They differ in
error style, paging behaviour and auth nuance; knowing which family a
cmdlet belongs to predicts its behaviour (Cs* voice cmdlets are the ones
with the long tail of versioned breaking changes — pin module versions,
read release notes before upgrading, the admin-surfaces module's rule).
Auth contexts (the operational decision)
- Interactive (human + MFA): admin work.
- App-only (certificate + application): unattended automation — the serv365 model: cert in a vault, app registration with least roles, NO stored passwords ever. Coverage note from our own execution audit: the overwhelming majority of Get-* surface works app-only; the exceptions get RECORDED (the honest-gaps discipline), because an automation that silently skips is worse than one that reports 'not served'.
Patterns that survive production
- Read-only by construction where possible (the serv365 constitution: Get-* allowlist) — a compromised reporting job should be boring.
- Throttling-aware: bulk reads paced with retry-after respect; the module + service WILL throttle store-scale loops.
- Batch for writes:
New-CsBatchPolicyAssignmentOperationfor population-scale policy moves — then READ THE OPERATION RESULT (the assignment-engine module's rule: completion is not success). - Idempotent scripts: desired-state style (check, then set if different) — reruns become safe, and your diffs become meaningful.
- Version pinning in CI: the module version is part of the script's contract; upgrades are deliberate events with a changelog read.
What to watch (proofs)
- Session truth:
Get-CsTenant/Get-CsOnlineUser -ResultSize 1as the connectivity+auth canary at script start — fail fast with a named cause. - Throttle encounters: retry-after events in your automation logs — rising counts = pace redesign before the service does it for you.
- Batch outcomes: operation results persisted per run (serv365's command-execution audit pattern: every cmdlet run, its outcome, stored) — the 'what did the script actually do' answer, forever.
- Version drift: module version logged per run — the correlation column for 'it broke on Tuesday' (Tuesday's run shows the new version; the release notes show the removed parameter).