<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Microsoft Graph on DR.365</title><link>https://blog.dr365.io/de/tags/microsoft-graph/</link><description>Recent content in Microsoft Graph on DR.365</description><generator>Hugo -- gohugo.io</generator><language>de-DE</language><lastBuildDate>Wed, 14 Oct 2026 07:00:00 +0200</lastBuildDate><atom:link href="https://blog.dr365.io/de/tags/microsoft-graph/index.xml" rel="self" type="application/rss+xml"/><item><title>Auf Menschentempo ausgelegt: Was Anthropics neue Versionskontrolle für die IT-Strategie bedeutet</title><link>https://blog.dr365.io/de/p/agent-scale-enterprise-it-strategy/</link><pubDate>Wed, 14 Oct 2026 07:00:00 +0200</pubDate><guid>https://blog.dr365.io/de/p/agent-scale-enterprise-it-strategy/</guid><description>&lt;img src="https://blog.dr365.io/p/agent-scale-enterprise-it-strategy/cover.png" alt="Featured image of post Auf Menschentempo ausgelegt: Was Anthropics neue Versionskontrolle für die IT-Strategie bedeutet" /&gt;&lt;p&gt;Im Mai 2026 hat Anthropic rund 2.500 Code-Änderungen pro Tag in sein Monorepo gemergt. Im September waren es über 30.000. Git und die Mirror-Infrastruktur drumherum kamen nicht mehr hinterher, also hat ein Team aus sieben Leuten ein eigenes Versionskontrollsystem gebaut und das komplette Monorepo in fünf Monaten migriert (&lt;a class="link" href="https://www.anthropic.com/engineering/redesigning-source-control" target="_blank" rel="noopener"
 &gt;Anthropic Engineering&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Kaum jemand, der das hier liest, wird ein Versionskontrollsystem bauen. Darum geht es bei der Geschichte auch nicht. Jede Organisation hat Prozesse, die auf das Tempo von Menschen ausgelegt sind: Change Advisory Boards, Vier-Augen-Freigaben, Access Reviews, CI-Pipelines, Budgets in Personentagen. Sobald Agents einen großen Teil der Arbeit erledigen, werden genau diese Prozesse zum Engpass. Die Frage ist, welche davon du umbaust, bevor sie brechen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kurz gesagt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agents werden zu den Hauptnutzern deiner Systeme. Architekturentscheidungen sollten von Maschinen-Clients ausgehen, die immer online sind und APIs in hoher Frequenz aufrufen.&lt;/li&gt;
&lt;li&gt;Review und Freigabe müssen weg von „ein Mensch hat alles angesehen“ hin zu Regeln, die festlegen, wo ein Mensch hinsehen muss.&lt;/li&gt;
&lt;li&gt;Jeder Agent braucht eine Identität, eine verantwortliche Person und eine Kostenstelle. Ohne diese drei kannst du Agentenarbeit weder steuern noch budgetieren.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="was-anthropic-tatsächlich-geändert-hat"&gt;Was Anthropic tatsächlich geändert hat
&lt;/h2&gt;&lt;p&gt;In den Schlagzeilen heißt es „Anthropic hat Git rausgeworfen“. Der Engineering-Beitrag selbst ist vorsichtiger. Das neue System heißt Scion, das Review-Werkzeug Antique. Anthropic schreibt ausdrücklich, dass Scion kein allgemeiner Ersatz für Git ist, weil dafür die gesamte Entwicklungs-Toolchain ersetzt werden müsste. Veröffentlicht wurde das Design, damit Git-Plattformen Teile davon übernehmen können.&lt;/p&gt;
&lt;p&gt;Warum sie es trotzdem gemacht haben, zeigen die Zahlen. Die Historie des Main-Branch umfasst fast 100 GB, eine komprimierte Arbeitskopie über 25 GB, und die CI zieht rund 25 Millionen Checkouts pro Tag. Git ist für verteilte Clients gebaut, die offline arbeiten. Die Clients bei Anthropic sind fast ausschließlich Agents und Jobs, die immer online sind. Scion verlagert die teure Arbeit auf den Server: Commits, Merges, Rebases, Historie und Blame laufen dort, Clients bekommen schlanke, virtualisierte Checkouts, die Dateien bei Bedarf nachladen, und vieles ist per API ganz ohne lokales Repository nutzbar. Laut Beitrag braucht die neue Infrastruktur etwa 200-mal weniger CPU und Speicher als die alten Git-Mirrors, CI-Checkouts dauern Sekunden statt Minuten.&lt;/p&gt;
&lt;p&gt;Drei Entscheidungen aus dem Beitrag sind über Versionskontrolle hinaus relevant:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Es gibt keine Merge Queue mit globalem Lock. Anthropic hat stattdessen in Tests nach dem Merge und vor dem Deployment investiert. Konflikte zwischen parallelen Änderungen kommen vor, und Claude behebt sie meist schneller, als ein Mensch sie bemerken würde.&lt;/li&gt;
&lt;li&gt;Antique kann semantische Regeln für Freigaben abbilden. Eine Änderung nur an Kommentaren wird anders behandelt als eine Änderung an sensibler Logik, damit menschliche Reviewer ihre Zeit dort verbringen, wo es zählt.&lt;/li&gt;
&lt;li&gt;Zugriffssteuerung auf Repository- und Verzeichnisebene war von Anfang an eingebaut, nicht nachträglich ergänzt.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="agents-sind-die-neuen-hauptnutzer"&gt;Agents sind die neuen Hauptnutzer
&lt;/h2&gt;&lt;p&gt;Die erste Lehre betrifft die Architektur. Die meisten Unternehmenssysteme gehen von einem Menschen vor einem Bildschirm aus. Agents verhalten sich anders: Sie pollen, sie laufen parallel, und Mittagspause machen sie auch keine.&lt;/p&gt;
&lt;p&gt;In Microsoft 365 sieht man das heute schon am Throttling von Microsoft Graph. Microsoft nennt zwei typische Ursachen: viele Anfragen über alle Anwendungen eines Tenants hinweg und viele Anfragen einer Anwendung über alle Tenants hinweg. Regelmäßiges Abfragen einer Ressource und wiederholtes Durchsuchen von Collections werden ausdrücklich als Muster genannt, die zu Throttling führen. Empfohlen werden stattdessen Delta Queries und Change Notifications, für große Datenmengen verweist Microsoft auf Graph Data Connect statt der REST-APIs (&lt;a class="link" href="https://learn.microsoft.com/graph/throttling" target="_blank" rel="noopener"
 &gt;Microsoft Learn&lt;/a&gt;). SharePoint Online geht noch einen Schritt weiter: Eine Anwendung, die Limits dauerhaft überschreitet, kann komplett blockiert werden (&lt;a class="link" href="https://learn.microsoft.com/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online" target="_blank" rel="noopener"
 &gt;Microsoft Learn&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Diese Hinweise wurden für Integrationsentwickler geschrieben. Inzwischen gelten sie für jeden Agent, der im Auftrag von jemandem Postfächer, Sites oder Teams-Kanäle liest. Wenn ich ein Agent-Szenario bewerte, frage ich deshalb zuerst, wie es Änderungen erkennt, und erst danach, was es tut. Ein Agent, der alle zehn Minuten eine Dokumentbibliothek komplett durchsucht, läuft im Pilot einwandfrei und wird zum Problem, wenn 40 Abteilungen ihn kopieren.&lt;/p&gt;
&lt;p&gt;Für eigene Systeme gilt dasselbe in umgekehrter Richtung. Wenn Agents die Hauptnutzer einer internen Plattform werden, braucht sie eine ordentliche API, Change Feeds und Limits pro Client. Eine Weboberfläche mit einem Scraping-Agent davor ist der Git-Mirror deiner Organisation: Sie funktioniert, bis das Volumen sich verzehnfacht.&lt;/p&gt;
&lt;h2 id="review-nach-absicht-statt-zeile-für-zeile"&gt;Review nach Absicht statt Zeile für Zeile
&lt;/h2&gt;&lt;p&gt;Die zweite Lehre betrifft Kontrollprozesse. Das Team bei Anthropic prüft weiterhin jede Änderung, aber es prüft die Absicht und nicht jede Zeile. Ihre wichtigste Aufgabe ist nach eigener Beschreibung, Claude „Nein“ zu sagen: wenn Systemgrenzen verletzt werden oder Claude wegen hypothetischer Bedenken überkonstruiert.&lt;/p&gt;
&lt;p&gt;In regulierten Umgebungen ist das der unbequeme Teil. Viele Change-Prozesse versprechen implizit, dass eine qualifizierte Person alles geprüft hat. Bei 30.000 Änderungen am Tag lässt sich dieses Versprechen nicht halten, und ehrlich gesagt wurde es oft schon bei 30 pro Woche nicht gehalten. Das CAB, das in 45 Minuten einen Stapel Changes durchwinkt, prüft vor allem, ob das Formular vollständig ist.&lt;/p&gt;
&lt;p&gt;Nach meiner Erfahrung wollen Auditoren Belege dafür sehen, dass Änderungen kontrolliert und nachvollziehbar sind. NIS2 verlangt Risikomanagementmaßnahmen, zu denen auch Sicherheit bei Entwicklung und Wartung gehört; dass ein Mensch jede Zeile liest, schreibt die Richtlinie nicht vor. Damit bleibt Raum für ein Modell, das ITIL als Standard Changes kennt, angewendet auf die Arbeit von Agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Geringes Risiko&lt;/strong&gt; (Dokumentation, Tests, Formatierung, Konfiguration innerhalb definierter Leitplanken): automatische Prüfungen, kein verpflichtendes menschliches Review, vollständige Protokollierung.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mittleres Risiko&lt;/strong&gt; (Geschäftslogik, Integrationen): menschliches Review von Absicht und Testnachweisen, mit der Zusammenfassung des Agents als Grundlage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hohes Risiko&lt;/strong&gt; (Authentifizierung, Berechtigungen, Datenflüsse über Vertrauensgrenzen, alles Regulierte): Review Zeile für Zeile durch eine benannte Person, wie bisher.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Was über die Stufe entscheidet, muss eine Regel sein und kein Bauchgefühl. Anthropic bildet das im Review-Werkzeug ab, du kannst es in Branch Protection Rules, CODEOWNERS-Dateien oder einem Genehmigungsflow in Power Automate abbilden. Die Regel selbst ist die Kontrolle, die ein Auditor sehen will.&lt;/p&gt;
&lt;p&gt;Bei einem Teil des Anthropic-Ansatzes wäre ich vorsichtig: Prüfungen hinter den Merge zu verlegen. Für eine interne Entwicklerplattform ist das ein vertretbarer Tausch. Für ein System in einer KRITIS-Umgebung, bei dem eine fehlerhafte Änderung direkt in Produktion landen kann, würde ich das nicht machen. Die Absicherung muss vor dem Deployment sitzen, auch wenn sie nicht mehr vor dem Merge sitzt.&lt;/p&gt;
&lt;h2 id="jeder-agent-braucht-eine-identität-und-einen-verantwortlichen"&gt;Jeder Agent braucht eine Identität und einen Verantwortlichen
&lt;/h2&gt;&lt;p&gt;Anthropic hat die Zugriffssteuerung in Scion vom ersten Tag an eingebaut, bis auf Verzeichnisebene. In Microsoft 365 entspricht dem die Identitätsschicht für Agents. Microsoft Entra Agent ID gibt Agents eigene Identitäten im Verzeichnis, erzeugt aus Agent Identity Blueprints. Jede Agent-Identität braucht einen menschlichen Sponsor, der für Zweck, Lebenszyklus und Access Reviews verantwortlich ist. Verlässt der Sponsor das Unternehmen, geht die Verantwortung auf seine Führungskraft über. Conditional Access und Access Packages aus dem Entitlement Management gelten auch für Agents (&lt;a class="link" href="https://learn.microsoft.com/entra/id-governance/agent-id-governance-overview" target="_blank" rel="noopener"
 &gt;Microsoft Learn&lt;/a&gt;). Stand Oktober 2026 ist Identity Governance für Agents als Preview gekennzeichnet, und die Lizenzierung hängt an Microsoft 365 E7 oder Agent 365. Prüf die aktuellen Bedingungen, bevor du damit planst.&lt;/p&gt;
&lt;p&gt;Darüber liegt in Microsoft Agent 365 die Registry als gemeinsames Inventar für Microsoft- und Fremd-Agents, inklusive der Anzahl an Agents ohne Besitzer (&lt;a class="link" href="https://learn.microsoft.com/microsoft-365/admin/manage/agent-registry" target="_blank" rel="noopener"
 &gt;Microsoft Learn&lt;/a&gt;). Die Governance-Seite habe ich ausführlicher im &lt;a class="link" href="https://blog.dr365.io/de/p/agent-lifecycle-agent-builder-copilot-studio/" &gt;Beitrag zum Agent Lifecycle&lt;/a&gt; beschrieben.&lt;/p&gt;
&lt;p&gt;Strategisch heißt das: Ein Agent, der unter einem geteilten Dienstkonto oder mit den delegierten Rechten einer Person läuft, lässt sich im Audit-Log nicht unterscheiden, nicht separat drosseln und nicht separat abrechnen. Das später für Hunderte Agents nachzuziehen, ist genau die Art Projekt, für die niemand Budget freigibt.&lt;/p&gt;
&lt;h2 id="agentenarbeit-messen"&gt;Agentenarbeit messen
&lt;/h2&gt;&lt;p&gt;Beim Budget bricht es an derselben Stelle. Das Controlling rechnet in den meisten IT-Organisationen noch in Personentagen, und für Agentenarbeit gibt es in diesem Modell keine Zeile. Ein praktikabler Weg ist, Agent-Sitzungen über ein AI Gateway zu leiten. Dann lässt sich jedes Token und jede Stunde Laufzeit einem Projekt und einem Repository zuordnen und mit echten Preisen bewerten.&lt;/p&gt;
&lt;p&gt;Ein Feature, das letztes Jahr 20 Tage gebraucht hat und dieses Jahr 3 Tage Review plus Agentenlaufzeit, passt nicht in dieses Modell. Agentenstunden zu zählen ist ein Anfang, aber Stunden sind eine Input-Kennzahl. Wissen willst du die Kosten pro akzeptierter Änderung: Tokens und Laufzeit plus die menschliche Zeit für Review, Nacharbeit und die Fälle, in denen jemand „Nein“ sagen musste. Ohne den menschlichen Anteil sieht Agentenarbeit billiger aus, als sie ist.&lt;/p&gt;
&lt;p&gt;Für Microsoft-Agents sammelt die Observability in Agent 365 Aktivitätsdaten und soll Kennzahlen wie Nutzung und Zeitersparnis liefern (&lt;a class="link" href="https://learn.microsoft.com/microsoft-agent-365/admin/monitor-agents" target="_blank" rel="noopener"
 &gt;Microsoft Learn&lt;/a&gt;). Das deckt einen Teil des Bildes ab. Coding-Agents außerhalb von Microsoft 365 brauchen eine eigene Zuordnung, und dort kommt der Gateway-Ansatz ins Spiel.&lt;/p&gt;
&lt;!-- TODO Daniel: Optional eigene Beobachtung ergänzen, wie Agentenkosten bei euch heute verbucht werden (verallgemeinert, ohne Kundennamen). --&gt;
&lt;h2 id="entscheidungen-für-die-nächsten-zwölf-monate"&gt;Entscheidungen für die nächsten zwölf Monate
&lt;/h2&gt;&lt;p&gt;Anthropic erwartet, dass andere Organisationen in den nächsten sechs bis zwölf Monaten auf diese Art Problem stoßen. Auch wenn dein Zeitplan länger ist, diese Entscheidungen würde ich jetzt treffen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Menschlich getaktete Kontrollen erfassen.&lt;/strong&gt; Liste jede Freigabe, jedes Review und jeden Pipeline-Schritt auf, der von einer Person und einem Arbeitstag ausgeht. Markiere, was beim zehnfachen Volumen bricht.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risikostufen für Änderungen einführen.&lt;/strong&gt; Schreib auf, welche Änderungen einen Menschen brauchen, welche nur eine Prüfung der Absicht und welche nur Protokollierung. Mach die Regel maschinenlesbar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents eigene Identitäten geben.&lt;/strong&gt; Keine geteilten Dienstkonten, jeder Agent mit Sponsor, Berechtigungen über Access Packages mit Ablaufdatum.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrationen für Maschinen-Clients auslegen.&lt;/strong&gt; Delta Queries, Change Notifications und API-Budgets statt Polling und Scraping.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentenkosten zuordnen.&lt;/strong&gt; Tokens und Laufzeit pro Projekt plus die menschliche Review-Zeit, ab dem ersten produktiven Agent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Was ich nicht tun würde: Anthropics Werkzeuge nachbauen. Deren Problem waren 25 Millionen Checkouts am Tag. Deins ist wahrscheinlicher ein Change-Prozess, der zwei Wochen für eine Konfigurationsänderung braucht, die ein Agent in zehn Minuten vorbereitet hat. Dort fängst du an.&lt;/p&gt;
&lt;h2 id="quellen"&gt;Quellen
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Anthropic Engineering: &lt;a class="link" href="https://www.anthropic.com/engineering/redesigning-source-control" target="_blank" rel="noopener"
 &gt;Redesigning source control at Anthropic&lt;/a&gt; (13. Oktober 2026)&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a class="link" href="https://learn.microsoft.com/graph/throttling" target="_blank" rel="noopener"
 &gt;Microsoft Graph throttling guidance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a class="link" href="https://learn.microsoft.com/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online" target="_blank" rel="noopener"
 &gt;Avoid getting throttled or blocked in SharePoint Online&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a class="link" href="https://learn.microsoft.com/entra/id-governance/agent-id-governance-overview" target="_blank" rel="noopener"
 &gt;Governing agent identities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a class="link" href="https://learn.microsoft.com/microsoft-365/admin/manage/agent-registry" target="_blank" rel="noopener"
 &gt;Manage agent registry in Microsoft 365 admin center&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a class="link" href="https://learn.microsoft.com/microsoft-agent-365/admin/monitor-agents" target="_blank" rel="noopener"
 &gt;Agent 365 observability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;EUR-Lex: &lt;a class="link" href="https://eur-lex.europa.eu/eli/dir/2022/2555/oj" target="_blank" rel="noopener"
 &gt;Richtlinie (EU) 2022/2555 (NIS2)&lt;/a&gt;, Artikel 21&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>PowerShell oder Microsoft Graph? Die passende Schnittstelle wählen und Modulkonflikte beheben</title><link>https://blog.dr365.io/de/p/powershell-vs-microsoft-graph-module-conflicts/</link><pubDate>Sun, 11 Oct 2026 07:00:00 +0200</pubDate><guid>https://blog.dr365.io/de/p/powershell-vs-microsoft-graph-module-conflicts/</guid><description>&lt;img src="https://blog.dr365.io/p/powershell-vs-microsoft-graph-module-conflicts/cover.png" alt="Featured image of post PowerShell oder Microsoft Graph? Die passende Schnittstelle wählen und Modulkonflikte beheben" /&gt;&lt;p&gt;Hinter „Machen wir das mit PowerShell oder mit Graph?“ stecken zwei Fragen: &lt;em&gt;Welche Schnittstelle bietet überhaupt, was ich brauche?&lt;/em&gt; und &lt;em&gt;Wie läuft das Ding in sechs Monaten, wenn keiner mehr draufschaut?&lt;/em&gt; Und wer schon einmal das Graph-PowerShell-SDK mit PnP.PowerShell oder dem Exchange-Online-Modul in einem Skript kombiniert hat, kennt die dritte Frage, die erst gestellt wird, wenn es knallt: &lt;em&gt;Laufen diese Module überhaupt zusammen?&lt;/em&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Kurz gesagt&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Exchange Online PowerShell&lt;/strong&gt; für Exchange-Administration (Postfachberechtigungen, Transportregeln, Organisationseinstellungen). Graph deckt das größtenteils nicht ab.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Graph&lt;/strong&gt; für Identitäten, dienstübergreifende Daten und alles, was eine &lt;em&gt;Anwendung&lt;/em&gt; tut: Integrationen, Mailversand, Reporting. Für den Postfachzugriff durch Anwendungen ist Graph die Schnittstelle, auf die du baust.&lt;/li&gt;
&lt;li&gt;Die klassische Falle beim Kombinieren: &lt;strong&gt;Assembly-Konflikte&lt;/strong&gt; (&lt;code&gt;Microsoft.Identity.Client&lt;/code&gt;, &lt;code&gt;Microsoft.Graph.Core&lt;/code&gt;, &lt;code&gt;Azure.Core&lt;/code&gt; …) zwischen Microsoft.Graph, PnP.PowerShell, ExchangeOnlineManagement und Az. Die Verbindungsreihenfolge ist Glückssache; &lt;strong&gt;Prozess-Isolation und weniger Module&lt;/strong&gt; sind die eigentliche Lösung.&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h2 id="wofür-du-dich-tatsächlich-entscheidest"&gt;Wofür du dich tatsächlich entscheidest
&lt;/h2&gt;&lt;p&gt;Das Microsoft-Graph-PowerShell-SDK &lt;em&gt;ist&lt;/em&gt; PowerShell und ruft unter der Haube Graph auf. Gewählt wird also zwischen zwei Arten von Schnittstellen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dienstspezifische Admin-Module:&lt;/strong&gt; ExchangeOnlineManagement, MicrosoftTeams, PnP.PowerShell für SharePoint. Sie sprechen mit den Admin-Schnittstellen eines Workloads und bieten Dinge, die es in Graph schlicht nicht gibt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Graph:&lt;/strong&gt; eine REST-API für Entra ID, Mail, Kalender, Dateien, Teams, Planner und vieles mehr, aufrufbar von überall: Graph-PowerShell-SDK, &lt;code&gt;Invoke-RestMethod&lt;/code&gt;, C#, Python, Logic Apps oder ein Ticketsystem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Welches von beiden passt, hängt zuerst davon ab, &lt;em&gt;welche Schnittstelle das überhaupt kann&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="wo-was-gewinnt"&gt;Wo was gewinnt
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Aufgabe&lt;/th&gt;
					&lt;th&gt;Meine Wahl&lt;/th&gt;
					&lt;th&gt;Warum&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Full Access / Send As, Transportregeln, organisationsweite Exchange-Einstellungen&lt;/td&gt;
					&lt;td&gt;Exchange Online PowerShell&lt;/td&gt;
					&lt;td&gt;Dafür gibt es keine Graph-Endpunkte. Die neue Exchange Online Admin API (Preview) deckt nur einen kleinen Ausschnitt ab, etwa Ordnerberechtigungen und Send on Behalf.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Benutzer, Gruppen, Lizenzen, App-Registrierungen in Entra ID&lt;/td&gt;
					&lt;td&gt;Graph (SDK oder REST)&lt;/td&gt;
					&lt;td&gt;Das ist Graphs Heimspiel.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Eine Anwendung sendet oder liest Mails (Ticketsystem, Workflows)&lt;/td&gt;
					&lt;td&gt;Graph&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sendMail&lt;/code&gt; bzw. Message-Endpunkte mit OAuth, eingegrenzt über RBAC for Applications.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Site-Provisioning, Templates, SharePoint-Berechtigungen&lt;/td&gt;
					&lt;td&gt;PnP.PowerShell&lt;/td&gt;
					&lt;td&gt;Für Admin-Aufgaben deutlich mächtiger als Graphs SharePoint-Schnittstelle.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Teams-Richtlinien (Besprechungen, Telefonie, Messaging)&lt;/td&gt;
					&lt;td&gt;MicrosoftTeams-Modul&lt;/td&gt;
					&lt;td&gt;Richtlinien leben in der Teams-Admin-Schnittstelle, nicht in Graph.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Dienstübergreifendes Reporting (Benutzer + Lizenzen + Anmeldungen + Gruppen)&lt;/td&gt;
					&lt;td&gt;Graph&lt;/td&gt;
					&lt;td&gt;Eine API, ein Auth-Modell, Paging und &lt;code&gt;$select&lt;/code&gt; inklusive.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Meine Faustregel: &lt;strong&gt;Führt ein Mensch es aus, nimm das Modul, das am nächsten am Workload ist. Führt eine Anwendung es aus, nimm Graph&lt;/strong&gt; – und gib dieser Anwendung genau die Rechte, die sie braucht, und keine mehr.&lt;/p&gt;
&lt;h2 id="praxisbeispiel-mail-integrationen"&gt;Praxisbeispiel: Mail-Integrationen
&lt;/h2&gt;&lt;p&gt;Der LinkedIn-Post, der diesen Artikel angestoßen hat, beschreibt die Modernisierung einer ServiceNow-Mailintegration, die Mails jetzt über Microsoft Graph sendet und empfängt. Hier arbeitet eine Anwendung mit Postfächern, kein Mensch, und genau da passt Graph: OAuth, granulare Berechtigungen und ein sauberer Audit-Trail. Eine Mail zu senden ist ein einziger Aufruf:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Microsoft Graph v1.0 – send mail as the service mailbox (app-only)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Required application permission: Mail.Send (scoped via RBAC for Applications, see below)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ticket INC0012345 updated&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;contentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Your ticket has been updated.&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;toRecipients&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;emailAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;adele.vance@contoso.com&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;saveToSentItems&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;$true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Invoke-MgGraphRequest&lt;/span&gt; &lt;span class="n"&gt;-Method&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Uri&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://graph.microsoft.com/v1.0/users/servicedesk@contoso.com/sendMail&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Body&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;ConvertTo-Json&lt;/span&gt; &lt;span class="n"&gt;-Depth&lt;/span&gt; &lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;-ContentType&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Was ich aus Sicht regulierter Umgebungen ergänzen würde: Eine App mit der Anwendungsberechtigung &lt;code&gt;Mail.Send&lt;/code&gt; darf standardmäßig als &lt;em&gt;jedes&lt;/em&gt; Postfach im Tenant senden. Das möchtest du keinem Auditor erklären. Mit &lt;strong&gt;RBAC for Applications in Exchange Online&lt;/strong&gt; grenzt du den Service Principal auf die Postfächer ein, die er wirklich braucht:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Exchange Online PowerShell – scope a ticketing app to its service mailboxes only&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Prerequisite: the Entra app has NO tenant-wide Mail.Send consent (otherwise permissions add up)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# IDs from &amp;#34;Enterprise applications&amp;#34; in Entra, not from &amp;#34;App registrations&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;New-ServicePrincipal&lt;/span&gt; &lt;span class="n"&gt;-AppId&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;app-id&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;-ObjectId&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;service-principal-object-id&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;-DisplayName&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ticketing&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;New-ManagementScope&lt;/span&gt; &lt;span class="n"&gt;-Name&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ticketing-Mailboxes&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-RecipientRestrictionFilter&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CustomAttribute10 -eq &amp;#39;Ticketing&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;New-ManagementRoleAssignment&lt;/span&gt; &lt;span class="n"&gt;-App&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;service-principal-object-id&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Role&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Application Mail.Send&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-CustomResourceScope&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ticketing-Mailboxes&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Verify before you go live&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Test-ServicePrincipalAuthorization&lt;/span&gt; &lt;span class="n"&gt;-Identity&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;service-principal-object-id&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;-Resource&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;servicedesk@contoso.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die Ironie dabei: Graph-Berechtigungen konfigurierst du mit Exchange-PowerShell. Genau das meint der Original-Post mit „beides zusammen“.&lt;/p&gt;
&lt;h2 id="modulkonflikte-zwischen-graph-pnp-und-exo"&gt;Modulkonflikte zwischen Graph, PnP und EXO
&lt;/h2&gt;&lt;p&gt;Angenommen, du schreibst ein völlig vernünftiges Skript: Graph für Benutzerdaten, PnP für SharePoint, EXO für Postfächer. Auf deinem Rechner läuft es. In der nächsten Sitzung scheitert es dann mit etwas wie:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Could not load type &amp;#39;Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;from assembly &amp;#39;Microsoft.Identity.Client, Version=4.50.0.0&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;oder&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Method not found: &amp;#39;!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1.WithLogging(...)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="warum-das-passiert"&gt;Warum das passiert
&lt;/h3&gt;&lt;p&gt;Jedes dieser Module ist ein Binärmodul und bringt eigene Kopien gemeinsam genutzter .NET-Bibliotheken mit – allen voran &lt;strong&gt;MSAL&lt;/strong&gt; (&lt;code&gt;Microsoft.Identity.Client.dll&lt;/code&gt;), aber auch &lt;code&gt;Azure.Core&lt;/code&gt;, &lt;code&gt;Azure.Identity&lt;/code&gt;, &lt;code&gt;Microsoft.Graph.Core&lt;/code&gt; oder &lt;code&gt;System.Text.Json&lt;/code&gt;. PowerShell lädt Assemblies pro Prozess in einen gemeinsamen Kontext, und dort kann &lt;strong&gt;von einer Assembly mit gegebenem Namen nur eine Version geladen sein&lt;/strong&gt;. Wer zuerst lädt, gewinnt; das andere Modul läuft dann gegen eine Version, für die es nie gebaut wurde.&lt;/p&gt;
&lt;p&gt;Microsofts eigene PowerShell-Dokumentation beschreibt genau das: Das Ergebnis hängt davon ab, welches Modul zuerst geladen wurde, welcher Codepfad lief und ob die Abhängigkeit beim Import oder erst bei der ersten Nutzung geladen wird. Deshalb funktioniert dasselbe Skript mal, mal nicht, je nachdem, was du vorher in der Sitzung gemacht hast.&lt;/p&gt;
&lt;p&gt;Bekannte Kombinationen, die Ärger gemacht haben:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PnP.PowerShell + Microsoft.Graph&lt;/strong&gt;: Ältere PnP-Versionen brachten ein veraltetes &lt;code&gt;Microsoft.Graph.Core&lt;/code&gt; (1.25.x) und ältere MSAL-Versionen mit, wodurch &lt;code&gt;Connect-MgGraph&lt;/code&gt; und &lt;code&gt;Invoke-MgGraphRequest&lt;/code&gt; nach dem Laden von PnP scheiterten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ExchangeOnlineManagement + Microsoft.Graph&lt;/strong&gt;: eine lange Geschichte. EXO 3.5.1 brachte einen Konflikt mit &lt;code&gt;System.Text.Json&lt;/code&gt;; im Juni 2026 berichtete Tony Redmond, dass mit Graph SDK 2.38 und EXO 3.10 in PowerShell 7 &lt;em&gt;keine&lt;/em&gt; Verbindungsreihenfolge zuverlässig funktionierte: Die eine scheitert mit dem &lt;code&gt;Method not found&lt;/code&gt; oben, die andere mit einer &lt;code&gt;NullReferenceException&lt;/code&gt; beim Token-Abruf.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Az.Accounts + Microsoft.Graph&lt;/strong&gt;: dasselbe Muster mit &lt;code&gt;Azure.Core&lt;/code&gt; / &lt;code&gt;Azure.Identity&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="so-erkennst-du-es"&gt;So erkennst du es
&lt;/h3&gt;&lt;p&gt;Erste Prüfung: Was ist in der aktuellen Sitzung tatsächlich geladen?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Which version of the usual suspects is loaded in this session – and from which module folder?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$suspects&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Microsoft.Identity.Client&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Microsoft.Graph.Core&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Azure.Core&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Azure.Identity&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;System.Text.Json&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.AppDomain&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;GetAssemblies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Where-Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="py"&gt;Name&lt;/span&gt; &lt;span class="n"&gt;-in&lt;/span&gt; &lt;span class="nv"&gt;$suspects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Select-Object&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Assembly&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="py"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Version&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="py"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Location&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Zeigt &lt;code&gt;Location&lt;/code&gt; in den PnP-Ordner, während du &lt;code&gt;Connect-MgGraph&lt;/code&gt; aufrufst, hast du den Übeltäter.&lt;/p&gt;
&lt;p&gt;Zweite Prüfung: Welche Versionen bringen deine installierten Module mit? Diese Inventur macht Konflikte sichtbar, &lt;em&gt;bevor&lt;/em&gt; sie in Produktion zuschlagen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$modules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Microsoft.Graph.Authentication&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PnP.PowerShell&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ExchangeOnlineManagement&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Az.Accounts&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;MicrosoftTeams&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$dlls&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Microsoft.Identity.Client.dll&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Microsoft.Graph.Core.dll&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Azure.Core.dll&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Azure.Identity.dll&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Get-Module&lt;/span&gt; &lt;span class="n"&gt;-ListAvailable&lt;/span&gt; &lt;span class="n"&gt;-Name&lt;/span&gt; &lt;span class="nv"&gt;$modules&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;ForEach-Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;$module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Get-ChildItem&lt;/span&gt; &lt;span class="n"&gt;-Path&lt;/span&gt; &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ModuleBase&lt;/span&gt; &lt;span class="n"&gt;-Recurse&lt;/span&gt; &lt;span class="n"&gt;-Include&lt;/span&gt; &lt;span class="nv"&gt;$dlls&lt;/span&gt; &lt;span class="o"&gt;-File&lt;/span&gt; &lt;span class="n"&gt;-ErrorAction&lt;/span&gt; &lt;span class="n"&gt;SilentlyContinue&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;ForEach-Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Assembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;BaseName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Reflection.AssemblyName&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;GetAssemblyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="py"&gt;Version&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;FullName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Sort-Object&lt;/span&gt; &lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Format-Table&lt;/span&gt; &lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt; &lt;span class="n"&gt;-AutoSize&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Manche Module enthalten getrennte Builds für .NET Framework und .NET, du siehst also eventuell zwei Einträge pro Modul. Spannend wird es, wenn &lt;em&gt;dieselbe&lt;/em&gt; Assembly modulübergreifend in unterschiedlichen Versionen auftaucht.&lt;/p&gt;
&lt;h3 id="so-löst-du-es"&gt;So löst du es
&lt;/h3&gt;&lt;p&gt;In dieser Reihenfolge:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Lade nicht, was du nicht brauchst.&lt;/strong&gt; Ist PnP.PowerShell ohnehin verbunden, brauchst du das Graph-SDK oft gar nicht. &lt;code&gt;Invoke-PnPGraphMethod&lt;/code&gt; ruft Graph über die PnP-Verbindung auf (sofern deine PnP-App-Registrierung die nötigen Graph-Berechtigungen hat). Und wenn du das SDK brauchst: &lt;code&gt;Microsoft.Graph.Authentication&lt;/code&gt; plus die ein, zwei Submodule installieren, die du wirklich nutzt (oder nur &lt;code&gt;Invoke-MgGraphRequest&lt;/code&gt;), statt des kompletten Metamoduls &lt;code&gt;Microsoft.Graph&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Pro Prozess isolieren.&lt;/strong&gt; Assemblies gelten pro Prozess, getrennte Prozesse können also nicht kollidieren. In PowerShell 7 läuft &lt;code&gt;Start-Job&lt;/code&gt; in einem Kindprozess:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Graph work in its own process – app-only auth with a certificate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Required application permission: User.Read.All&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$auth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ClientId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;app-id&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;TenantId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;contoso.onmicrosoft.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Thumbprint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;cert-thumbprint&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Start-Job&lt;/span&gt; &lt;span class="n"&gt;-ArgumentList&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt; &lt;span class="n"&gt;-ScriptBlock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Connect-MgGraph&lt;/span&gt; &lt;span class="n"&gt;-ClientId&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ClientId&lt;/span&gt; &lt;span class="n"&gt;-TenantId&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;TenantId&lt;/span&gt; &lt;span class="n"&gt;-CertificateThumbprint&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Thumbprint&lt;/span&gt; &lt;span class="n"&gt;-NoWelcome&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Get-MgUser&lt;/span&gt; &lt;span class="n"&gt;-Filter&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;accountEnabled eq true&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;-All&lt;/span&gt; &lt;span class="n"&gt;-Property&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userPrincipalName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;department&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Select-Object&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserPrincipalName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Department&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Receive-Job&lt;/span&gt; &lt;span class="n"&gt;-Wait&lt;/span&gt; &lt;span class="n"&gt;-AutoRemoveJob&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Main session: PnP only – Graph&amp;#39;s assemblies were never loaded here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Connect-PnPOnline&lt;/span&gt; &lt;span class="n"&gt;-Url&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://contoso.sharepoint.com/sites/hr&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-ClientId&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ClientId&lt;/span&gt; &lt;span class="n"&gt;-Tenant&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;TenantId&lt;/span&gt; &lt;span class="n"&gt;-Thumbprint&lt;/span&gt; &lt;span class="nv"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Thumbprint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Der Job liefert deserialisierte Objekte zurück (Eigenschaften ja, Methoden nein), genau richtig, um Daten zwischen Schritten weiterzureichen. Wichtig: &lt;strong&gt;&lt;code&gt;Start-ThreadJob&lt;/code&gt; und &lt;code&gt;ForEach-Object -Parallel&lt;/code&gt; isolieren &lt;em&gt;nicht&lt;/em&gt;&lt;/strong&gt;. Sie laufen im selben Prozess und teilen sich die geladenen Assemblies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Runbooks und Pipelines aufteilen.&lt;/strong&gt; In Azure Automation getrennte Runtime Environments (PowerShell 7.4) pro Modulkombination statt einer „Alles drin“-Umgebung. In CI/CD ein Job pro Workload. Das bringt nebenbei sauberere Berechtigungen pro Identität, also Least Privilege gleich mit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Versionen bewusst pinnen.&lt;/strong&gt; &lt;code&gt;#Requires -Modules @{ ModuleName = 'ExchangeOnlineManagement'; RequiredVersion = '&amp;lt;tested-version&amp;gt;' }&lt;/code&gt; am Skriptanfang macht aus „nach dem Update kaputt“ ein „startet gar nicht erst“ – der deutlich bessere Fehlerfall. Module gezielt aktualisieren, nach einem Smoke-Test, der jede genutzte Modulkombination importiert und verbindet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Notlösung: Verbindungsreihenfolge und DLL-Tausch.&lt;/strong&gt; Eine bestimmte Reihenfolge beim Verbinden oder eine neuere &lt;code&gt;Microsoft.Identity.Client.dll&lt;/code&gt; in den Ordner eines anderen Moduls kopieren: Beides kursiert in der Community. Das hilft vielleicht über einen Tag, ist aber nicht supportet, wird beim nächsten &lt;code&gt;Update-Module&lt;/code&gt; überschrieben und hört, wie der EXO/Graph-Fall von 2026 zeigt, ohne Vorwarnung auf zu funktionieren. Produktive Automatisierung würde ich darauf nicht bauen.&lt;/p&gt;
&lt;h2 id="weitere-fallstricke"&gt;Weitere Fallstricke
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Windows PowerShell 5.1 und PowerShell 7 verhalten sich unterschiedlich. .NET Framework und .NET laden Assemblies anders; eine Kombination, die in 7 scheitert, kann in 5.1 funktionieren und umgekehrt. PnP.PowerShell 3.x setzt ohnehin PowerShell 7.4 oder neuer voraus – „dann eben 5.1“ ist für SharePoint keine Option.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-DisableWAM&lt;/code&gt; ist keine Lösung. Seit EXO 3.7.0 ist der Web Account Manager der Standard-Broker für interaktive Anmeldungen. &lt;code&gt;Connect-ExchangeOnline -DisableWAM&lt;/code&gt; umgeht Konflikte manchmal, Microsoft beschreibt es aber ausdrücklich als vorübergehende Maßnahme.&lt;/li&gt;
&lt;li&gt;App-only schlägt interaktiv. Zertifikatsbasierte Anmeldung umgeht die meisten WAM-/Broker-Probleme und ist für geplante Automatisierung ohnehin das Mittel der Wahl.&lt;/li&gt;
&lt;li&gt;Berechtigungen addieren sich. Bei RBAC for Applications wirken Entra-Consent und Exchange-Rollenzuweisung additiv. Ein tenantweiter &lt;code&gt;Mail.Send&lt;/code&gt;-Consent in Entra ID hebelt deine eingegrenzte Zuweisung stillschweigend aus.&lt;/li&gt;
&lt;li&gt;Die Exchange Online Admin API ist &lt;strong&gt;Preview&lt;/strong&gt; und bewusst schmal. Sie ergänzt EXO PowerShell, ersetzt es aber nicht.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Die Admin-Module liefern die Tiefe des jeweiligen Workloads, Graph gibt Anwendungen einen einheitlichen, nachvollziehbaren Zugang und ist damit der natürliche Ort für jede Postfach-Integration. Wenn du Module kombinierst, behandle sie wie Komponenten mit Abhängigkeiten: weniger laden, pro Prozess isolieren, Versionen pinnen und Updates testen, bevor deine Runbooks es für dich tun.&lt;/p&gt;
&lt;h2 id="quellen"&gt;Quellen
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/powershell/scripting/dev-cross-plat/resolving-dependency-conflicts" target="_blank" rel="noopener"
 &gt;Resolving PowerShell module assembly dependency conflicts – Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/powershell/microsoftgraph/troubleshooting" target="_blank" rel="noopener"
 &gt;Troubleshooting common errors in Microsoft Graph PowerShell – Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/graph/api/user-sendmail" target="_blank" rel="noopener"
 &gt;user: sendMail – Microsoft Graph v1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/exchange/permissions-exo/application-rbac" target="_blank" rel="noopener"
 &gt;Role Based Access Control for Applications in Exchange Online – Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/exchange/reference/admin-api-overview" target="_blank" rel="noopener"
 &gt;Overview of the Exchange Online Admin API (preview) – Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/troubleshoot/exchange/administration/wam-integration-issues" target="_blank" rel="noopener"
 &gt;Resolve issues in the Exchange Online PowerShell module after WAM integration – Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://pnp.github.io/powershell/articles/installation.html" target="_blank" rel="noopener"
 &gt;PnP PowerShell installation – PnP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://office365itpros.com/2026/06/22/powershell-woes-and-cmdlets/" target="_blank" rel="noopener"
 &gt;The Grief and Joys of New PowerShell Releases – Office 365 for IT Pros (Tony Redmond)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog-en.topedia.com/2024/04/fix-conflicts-between-pnppowershell-and-microsoftgraphauthentication-module/" target="_blank" rel="noopener"
 &gt;Fix conflicts between PnP.PowerShell and Microsoft.Graph.Authentication – topedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inspiriert von einem LinkedIn-Post von &lt;a class="link" href="https://www.linkedin.com/posts/anthony-samuel-m365-iam_powershell-vs-microsoft-graph-which-share-7514768232751243264-hjWG" target="_blank" rel="noopener"
 &gt;Anthony Samuel&lt;/a&gt;.&lt;/p&gt;</description></item></channel></rss>