Assembly Clashes Make Microsoft 365 PowerShell Frustrating
Assembly Clashes Happen too Often
In June, I reported a problem with V3.8 of the Exchange Online management PowerShell module when called by Azure Automation runbooks. The problem was caused by the removal of .NET6 support in the Exchange Online module, which meant that runbooks using the PowerShell V7.1 or V7.2 runtime engines couldn’t load. The Microsoft Graph PowerShell SDK did the same thing with the same effect, proving that developers don’t look much outside their own software to discover how problems might occur when software dependencies change.
The Authentication Assembly Dependency
Complex software often has some form of dependency. In the case above, it was the version of .NET that caused problems. New .NET versions appear and have a support schedule, so it’s understandable that software products should move to the latest supported version and want to discard versions that are no longer supported. What’s not understandable is when engineers make changes with no regard to what might happen to customer production scripts.
But an even more irritating problem that continues to happen is Microsoft’s failure to sort out the use of .NET assemblies across important PowerShell modules like the Microsoft Graph PowerShell SDK, Exchange Online management, and Microsoft Teams.
All the modules need to authenticate connections, so they call the Microsoft Authentication Library (MSAL) and load the Microsoft.Identity.Client assembly to allow clients to authenticate. An assembly is a building block for .NET applications. In this instance, the MSAL assembly contains the code necessary to allow an application (like a PowerShell module) to authenticate with Entra ID and obtain the necessary access tokens to work with data.
Connecting with Exchange and then the Graph
Sometimes the Microsoft 365 PowerShell modules fail to use the same version of the assembly, which means that an older version can be loaded into a session and cause a problem for a module loaded afterwards. Take this example using V3.9 of the Exchange Online management module and V2.30 of the Microsoft Graph PowerShell SDK:
PowerShell 7.5.3 Connect-Exchangeonline -showBanner:$false Connect-MgGraph -NoWelcome Connect-MgGraph: InteractiveBrowserCredential authentication failed: Method not found: '!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'.
Connect-ExchangeOnline runs first and authenticates, so the MSAL assembly it requires is loaded into the session. When Connect-MgGraph runs, it checks for a method that doesn’t exist in the loaded MSAL assembly and barfs. Microsoft’s support guidance for the Microsoft Graph PowerShell SDK recommends using the latest bits, but this problem happened with the latest available release.
The problem goes away if Connect-MgGraph is run before Connect-ExchangeOnline. When this happens, the Graph has the assembly it needs and the Exchange module is happy to use the later version of MSAL.
A Known Problem for Years
Assembly clashing between PowerShell modules has been a known problem for years. A recent issue posted to GitHub notes that Microsoft does not implement assembly loading properly because all assemblies are loaded globally (and so affect all modules loaded into the session) rather than in an application context (just for one module).
The mismatch of MSAL assemblies has been an issue for quite a while (here’s a similar problem report from August 2023). To be fair to Exchange Online, the Azure Accounts module has also experienced assembly clashing with the Microsoft Graph PowerShell SDK.
To be fair to the Microsoft Graph PowerShell SDK, assembly clashing is known between Exchange Online and Microsoft Teams. Figure 1 shows what happens when you attempt to run the Connect-MicrosoftTeams cmdlet (V7.3.1) after running Connect-ExchangeOnline:

It’s kind of weird that Connect-MicrosoftTeams isn’t recognized as a cmdlet. Everything works perfectly when Connect-MicrosoftTeams runs before Connect-ExchangeOnline.
No Change Without Consensus
Assembly clashes will continue until the Microsoft engineering groups coordinate development better to ensure common usage of important .NET assemblies. It doesn’t take much to communicate what version of an assembly a module needs so that everyone can reach consensus on the version modules use. Maybe Copilot could help. In the interim, the only solution is to make sure that the order scripts load modules doesn’t cause a problem, and to repeat that check after each release of important modules.