← Writing

2026-05-17 · Microsoft Teams · PowerShell

Teams-Policies, aber das Meeting endet wirklich

Letztes Quartal saßen wir mit sieben Leuten 90 Minuten in einem Raum, um Microsoft-Teams-Policies zu reviewen. Die meiste Zeit ging nicht in Entscheidungen. Sie ging in:

  • Den aktuellen Wert einer Einstellung suchen, deren genauen Namen niemand mehr wusste.
  • Diskutieren, ob der Default, den wir hatten, wirklich ein Default ist oder etwas, das ein früherer Admin vor Jahren mal angepasst hat.
  • Hin und her überlegen, was Microsoft heute empfiehlt und was unsere alte Baseline war.
  • Schätzen, wie viele Nutzerinnen und Nutzer eine Änderung tatsächlich betrifft.

Als wir dann endlich beim Entscheiden waren, ging das in zwanzig Minuten. Die anderen siebzig waren Datensucherei im Besprechungsraum. Anschließend hat ein Junior-Admin zwei Tage damit verbracht, die Entscheidungen in PowerShell-Befehle und Zuweisungen zu übersetzen. Die Hälfte landete auf der falschen Policy, weil die Meeting-Notizen nicht zu den Cmdlet-Namen passten.

Dieses Muster wiederholt sich jeden Audit-Zyklus. Also habe ich ein Tool geschrieben, das daraus etwas anderes macht.

Was es macht

Ein PowerShell-Script, drei Modi:

1. Export

Verbindet sich mit dem Tenant, findet jedes Get-CsTeams*-Policy- und Configuration-Cmdlet (typisch 70 bis 80 Stück), zieht jedes davon nach JSON und in ein flaches CSV, und schreibt ein einzelnes Excel-Workbook, das die Einstellungen nach Kategorie gruppiert. Jede Zeile enthält den aktuellen Wert, den empfohlenen Wert, einen Marker wenn beide abweichen, die Anzahl betroffener Nutzer und eine leere DECISION-Spalte fürs Meeting.

2. Meeting

Du öffnest das Workbook mit den Stakeholdern. Sie füllen die DECISION-Spalte. Niemand muss einen Cmdlet-Namen aus dem Kopf wissen oder ein zweites Fenster aufmachen. Die Empfehlung steht daneben. Die Zahl der betroffenen Nutzer auch.

3. Apply

Script nochmal starten, mit -ApplyDecisions path/to/edited.xlsx. Standardmäßig erzeugt es eine eigenständige .ps1, die alle Änderungen vor dem Ausführen lesbar enthält. Mit -DryRun siehst du, was sich ändern würde, ohne den Tenant anzufassen. Ohne diese Flags werden die Änderungen direkt angewendet.

Das ist der ganze Loop. Export, entscheiden, anwenden. Aus dem 90-Minuten-Meeting werden 20 Minuten echte Entscheidungen, und aus den zwei Tagen Nachbereitung wird Null.

Was mir wichtig war

Es funktioniert headless. -AuthMethod DeviceCode gibt dir einen Code, den du auf microsoft.com/devicelogin eingibst. Kein Browser nötig auf der Maschine, von der du es startest. Praktisch, wenn du auf einen Jumphost ssh’st und das Ding in eine Pipeline einbauen willst.

Review-Script als Default. Der Apply-Schritt geht nicht einfach los und ändert Dinge. Standardmäßig schreibt er ein Script, das du Zeile für Zeile lesen kannst. Audit-Teams mögen das. Junior-Admins, die gerade etwas auf Produktion ändern, mögen es noch mehr.

User-Impact ist echt, nicht generisch. Das Script zählt, wie viele Nutzer tatsächlich einer Non-Global-Policy zugewiesen sind, und zeigt das im Workbook. Wenn jemand im Meeting also sagt „lass uns das Feature deaktivieren", siehst du sofort, ob das 12 Leute betrifft oder 4.200.

Die Empfehlungen sind konservativ. Sie folgen der Microsoft-Baseline, nicht dem, was letzten Monat auf einem Security-Blog trendete. Wenn du anderer Meinung bist, übersteuere in der DECISION-Spalte. Das Tool besteht nicht darauf, dass du seine Empfehlung übernimmst.

Was es nicht macht

Ich will über die Kanten ehrlich sein:

  • Es ersetzt keinen echten CAB-Prozess. Es komprimiert nur den Datensammlungs-Teil. Das Entscheiden bleibt bei dir.
  • Es braucht Teams-Administrator-Rechte in deinem Tenant. Read-only reicht für Export, Write brauchst du für Apply.
  • Es ist PowerShell. Wenn euer Shop auf Bash und Python läuft und „Cmdlet" euch Ausschlag verursacht, werdet ihr damit nicht warm. PowerShell 5.1 auf Windows oder 7.2+ cross-platform laufen beide.
  • Es fasst Intune, Entra oder Call-Quality-Dashboards nicht an. Nur Teams-Policies, mit Absicht. Tools, die alles versuchen, machen meist eine Sache schlecht.

Warum es Open Source ist

Ich habe das für meine eigene Situation gebaut, und da ist nichts drin, was Wettbewerbsgeheimnis sein müsste. Die Teile, die tenant-spezifisch sind (eure Einstellungen, eure Entscheidungen, eure User-Zahlen) verlassen die Maschine nie. Das Script liest aus eurem Tenant und schreibt Dateien lokal.

Apache 2.0. Lesen, forken, PR schicken, oder die Idee nehmen und eine bessere Version schreiben. So oder so wird das nächste Teams-Policy-Meeting in einer anderen Firma kürzer.

Wenn du auf was Komisches stößt, mach ein Issue auf oder schreib mir auf LinkedIn. Ich fixe das wahrscheinlich am selben Abend, weil es vermutlich heißt, dass ich gleich in Produktion drüber stolpere.

Teams policies, but the meeting actually ends

Last quarter we sat in a room of seven people for 90 minutes to review Microsoft Teams policies. Most of the time was not spent deciding anything. It went into:

  • Finding the current value of a setting nobody could remember the exact name of.
  • Arguing whether the default we had was actually a default or something a former admin had changed years ago.
  • Going back and forth on what Microsoft now recommends and what the previous baseline was.
  • Wondering how many users a change would actually affect.

The decisions themselves, when we finally got to them, took maybe twenty minutes. The other seventy were data plumbing in a meeting room. Then a junior admin spent the next two days transcribing the decisions back into PowerShell commands and assignments. Half of those got applied to the wrong policy because the meeting notes did not match the cmdlet names.

That pattern repeats every audit cycle. So I wrote a tool that turns it into something else.

What it does

One PowerShell script, three modes:

1. Export

Connects to the tenant, discovers every Get-CsTeams* policy and configuration cmdlet (typically 70 to 80 of them), pulls each one to JSON and a flat CSV, and writes a single Excel workbook that groups the settings by category. Each row has the current value, the recommended value, a flag if they differ, the number of users affected, and an empty DECISION column for the meeting.

2. Meeting

You open the workbook with the stakeholders. They fill in the DECISION column. Nobody has to remember a cmdlet name or open a second window. The recommendation column is right there. The user-impact number is right there.

3. Apply

Run the script again with -ApplyDecisions path/to/edited.xlsx. By default it produces a standalone .ps1 review script with all the changes ready to inspect before running. Use -DryRun to see what would change without touching the tenant. Use it without those flags and it applies the changes directly.

That is the whole loop. Export, decide, apply. The 90-minute meeting becomes 20 minutes of actual decisions, and the two days of after-meeting transcription become zero.

The things I care about

It works from a headless session. Pass -AuthMethod DeviceCode and you get a code to enter at microsoft.com/devicelogin. No browser needed on the box you are running it from. Useful when you ssh into a jump host and want to script this into a pipeline.

Review-script-by-default. The apply step does not just go and change things. By default it writes a script you can read line by line. Audit teams like that. Junior admins about to apply changes to production like that even more.

User impact is real, not generic. The script counts how many users are actually assigned to a non-global policy and shows it in the workbook. So when somebody in the meeting says "let us disable that feature" you immediately see whether that affects 12 people or 4,200.

The recommendations are conservative. They follow Microsoft baseline guidance, not whatever was trending on a security blog last month. If you disagree, override in the DECISION column. Nothing in the tool insists you do what it recommends.

What it does not do

I want to be honest about the edges:

  • It does not replace a real CAB process. It compresses the data-gathering part. The deciding is still on you.
  • It needs Teams Administrator rights in your tenant. Read-only is enough for export, write is needed for apply.
  • It is PowerShell. If your shop runs on Bash and Python and the word "cmdlet" gives you a rash, you will not enjoy this. PowerShell 5.1 on Windows or 7.2+ cross-platform both work.
  • It does not touch Intune, Entra, or call-quality dashboards. Just Teams policies, on purpose. Tools that try to do everything tend to do the one thing badly.

Why it is open source

I built this for my own situation and there is nothing in here that should be a competitive secret. The bits that are tenant-specific (your settings, your decisions, your user counts) never leave your machine. The script just reads from your tenant and writes files locally.

Apache 2.0. Read it, fork it, send a PR, or take the idea and write a better version. Either way the next Teams-policy meeting in some other company gets shorter.

If you run into something weird, file an issue or ping me on LinkedIn. I will probably fix it the same evening because it likely means I am about to hit it in production too.