<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PowerShell on DR.365</title><link>https://blog.dr365.io/de/tags/powershell/</link><description>Recent content in PowerShell on DR.365</description><generator>Hugo -- gohugo.io</generator><language>de-DE</language><lastBuildDate>Sun, 11 Oct 2026 07:00:00 +0200</lastBuildDate><atom:link href="https://blog.dr365.io/de/tags/powershell/index.xml" rel="self" type="application/rss+xml"/><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>