Repository navigation
Connect-MgGraph fails after Connect-ExchangeOnline #3394
Description
Activity
- addedstatus:waiting-for-triageAn issue that is yet to be reviewed or assignedAn issue that is yet to be reviewed or assignedtype:bugA broken experienceA broken experience
on Sep 10, 2025 FabienTschanz commented
on Sep 12, 2025 ContributorMore actionsThe issue is with the assembly context of the module. Microsoft does not implement the assembly loading context properly, leading to those assemblies being loaded globally instead of only in the application context it belongs to. This is something that occurs again and again and they don't fix it... Guess we have to wait until the next release fixes it (for another couple of months until the next one)...
Reacted by robinmalik, mark3grahams and Greg SmulkoThis has been an issue for years now as I remember having to inform colleagues to avoid doing this. Given that the Exchange team released a PowerShell snap-in just a few years ago despite modules being favoured since 2010, I'm not convinced they will be working collaboratively with more modern teams within Microsoft to help resolve this. I hope I'm wrong though.
Reacted by KevinPinel_QUT, mark3grahams, yllekz and bbdavidbbReacted by Maximilian OtterThis does work in PS5. It doesn't help when scripts also rely on PS7 only modules
Reacted by robinmalik- removedstatus:waiting-for-triageAn issue that is yet to be reviewed or assignedAn issue that is yet to be reviewed or assigned
on Oct 20, 2025 We are working with the EXO team to resolve this issue and ensure it should not happen again.
In the meantime if you reverse the order in which the
Connect-*cmdlets are called the cmdlets work as expected based on out testingReacted by Adam Dempsey, mark3grahams, robinmalik, Raimund Andrée, Maximilian Otter and PimpJuiceITGavin Barron (@gavinbarron) Is there any update regarding this issue?
It took more than a month to acknowledge the bug and now another month passed without a fix.
Since these are enterprise tools we need to manage our M365 services, I think there should be some kind of higher priority, rollback to working versions or some kind of communication at least.
I think there's no M365 admin center service incident, no message on the Exchange techcommunity Blog etc.Reacted by mark3grahams, Maximilian Otter, Andrew Maiman, mangle618, OneFreemanWill, vrststn, Levi and robinmaliklol, pretty insane that it's fixed by importing ExchangeOnlineManagement before importing any Microsoft.Graph.* modules
but it works... very satisfying fix tbh... simple, straight-forward, reproducible with minimal effort...I wonder what goes on that causes it to have issues if the Graph modules are imported first
Reacted by mark3grahamsFlorian Kolb (@Skaldhor) we're trying to work with the EXO team on a comprehensive fix.
I apologize that this is taking too long, but the reality here is that we have limited resources and the EXO team hasn't been willing to collaborate on a proper fix. So, while we could ship a fix that addresses this for the current versions without their collaboration, we'll wind up in the same broken state again when they ship again.
Reacted by robinmalikGavin Barron (@gavinbarron)
I understand there are internal collaboration issues at Microsoft and appreciate you being open about it and trying to achieve a future proof solution.However, from a customer/consumer point of view: This is a bug/issue in enterprise management tools we need and pay for (indirectly). I would expect this to be fixed "relatively" timely, especially since you already seem to know the issue, cause and (potential) fix.
Even without the EXO team you could publish a working version for now and work on a future proof solution with them in the background.Reacted by robinmalikI now have the reverse issue:
PS C:\> Connect-MgGraph Welcome to Microsoft Graph! Connected via delegated access using 14d82eec-204b-4c2f-b7e8-296a70dab67e Readme: https://aka.ms/graph/sdk/powershell SDK Docs: https://aka.ms/graph/sdk/powershell/docs API Docs: https://aka.ms/graph/docs NOTE: You can use the -NoWelcome parameter to suppress this message. NOTE: Sign in by Web Account Manager (WAM) is enabled by default on Windows systems and cannot be disabled when using the default ClientId. To disable WAM run Set-MgGraphOption -DisableLoginByWAM $true and then use a custom ClientId. PS C:\> Connect-ExchangeOnline Error Acquiring Token: System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Identity.Client.Platforms.Features.RuntimeBroker.RuntimeBroker..ctor(CoreUIParent uiParent, ApplicationConfiguration appConfig, ILoggerAdapter logger) at Microsoft.Identity.Client.Broker.BrokerExtension.<>c.<AddRuntimeSupport>b__3_0(CoreUIParent uiParent, ApplicationConfiguration appConfig, ILoggerAdapter logger) at Microsoft.Identity.Client.PlatformsCommon.Shared.AbstractPlatformProxy.CreateBroker(ApplicationConfiguration appConfig, CoreUIParent uiParent) at Microsoft.Identity.Client.Internal.Requests.InteractiveRequest.FetchTokensFromBrokerAsync(String brokerInstallUrl, CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.InteractiveRequest.GetTokenResponseAsync(CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.InteractiveRequest.ExecuteAsync(CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.RequestBase.<>c__DisplayClass11_1.<<RunAsync>b__1>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.Identity.Client.Utils.StopwatchService.MeasureCodeBlockAsync(Func`1 codeBlock) at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken) at Microsoft.Identity.Client.ApiConfig.Executors.PublicClientExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenInteractiveParameters interactiveParameters, CancellationToken cancellationToken) at Microsoft.Exchange.Management.AdminApiProvider.Authentication.MSALTokenProvider.GetAccessTokenAsync(String claims, String cmdletId) OperationStopped: Object reference not set to an instance of an object. PS C:\>Inverting the commands and connecting to ExchangeOnline before Graph works. (If I want to add MicrosoftTeams to the same session, I have to connect to it before ExchangeOnline because those two modules also constantly conflict with one another.)
PowerShell: 7.5.4
Microsoft.Graph: 2.35.1
ExchangeOnlineManagement: 3.9.2
MicrosoftTeams: 7.6.0This is really painful! Please write your PowerShell modules such that they will function regardless of what order they are loaded/started in.
Reacted by robinmalik and PimpJuiceITReacted by mark3grahams, PimpJuiceIT and robinmalikRidiculous, upon testing deprovisioning scripts post account termination, things not working even loading Exchange Online first. Now I have to spend time rewriting the logic in a way that works with the most up-to-date methods that work today to workaround the bugs (in all sections), and hope that it stays working or else redo it again on the next update for the next bug—I will remain hopeful it is not a continual issue that is reintroduced on the next release.
At least I run the module updates on a different VM machine for initial testing but would be nice for some consistency with updated modules. The order does seem to load to get a little further but run into other errors after that part of the logic is adjusted now. I modernized these scripts last round using a mix of Graph and Exchange Online commands. Now I need to figure out the order of logic for loading modules.
For now, I'll hold off on updating my main machine until something is released fixing the bugs that were introduced which I can validate work without slews of time needed rewriting scripts and testing logic. In my case, on-prem is the source of authority and syncs over to M365 Entra Connect but before terminating accounts, all on-prem and Azure/Entra/Exchange Online details need documented in a pre-term text file.
Working around this issue is a pain.
Gavin Barron (@gavinbarron) Let me add that not implementing ALC will never properly fix the issue: https://github.com/jborean93/PowerShell-ALC
Without that, it will always depend on the MSAL signatures and backward compatibility, and which one is loaded first...
I'm sure if you reach out to the PS team internally (i.e. Steve L), he'll happily point you in the right direction.For those looking for a temporary workaround to make your life slightly less miserable, Sam Erde (@SamErde) has build this workaround here: https://github.com/maester365/maester/blob/main/powershell/internal/Get-ModuleImportOrder.ps1#L1
Reacted by Sam Erde, robinmalik, Patrick and Chris H6 remaining items
While we wait for MS to fix it I've added ALC automated handling to my PowerShell builder
Install-Module PSPublishModuleImport-Module PSPublishModule -Force $exo = Import-IsolatedModule -Profile ExchangeOnlineManagement -PassThru $teams = Import-IsolatedModule -Profile MicrosoftTeams -PassThru $graph = Import-IsolatedModule -Profile MicrosoftGraphAuthentication -PassThru Connect-ExchangeOnline -ShowBanner:$false Connect-MicrosoftTeams Connect-MgGraph -NoWelcome Get-ConnectionInformation Get-Team -NumberOfThreads 1 Get-MgContext $exo, $teams, $graph | Format-Table ProfileName, ModuleName, ContextName
Import-Module Microsoft.Graph.Authentication -Force Import-Module PSPublishModule -Force $exo = Import-IsolatedModule -Profile ExchangeOnlineManagement -PassThru $exo | Format-List ProfileName, ModuleName, ContextName, IsolatedImportPath, WorkPath Connect-ExchangeOnline -ShowBanner:$false Get-EXOMailbox -ResultSize 1 | Select-Object DisplayName, PrimarySmtpAddress Disconnect-ExchangeOnline -Confirm:$false
What it does:
- Finds the real installed module, for example ExchangeOnlineManagement or MicrosoftTeams.
- Copies it to a temporary work folder.
- Generates a patched wrapper .psm1.
- Loads the module’s selected DLLs through a named .NET AssemblyLoadContext, for example:
- ExchangeOnlineManagement.ALC
- MicrosoftTeams.ALC
Imports the PowerShell commands from those isolated assemblies.
Preserves the module manifest/export surface so users still run normal commands:
- Connect-ExchangeOnline
- Get-EXOMailbox
- Connect-MicrosoftTeams
- Get-Team
This one proves it works also with DllPickle if that's your choice, but it shouldn't be nessecary
Import-Module Az.Storage -Force Import-Module PSPublishModule -Force $exo = Import-IsolatedModule -Profile ExchangeOnlineManagement -PassThru $exo | Format-List ProfileName, ModuleName, ContextName, IsolatedImportPath, WorkPath Connect-ExchangeOnline -ShowBanner:$false Get-ConnectionInformation Get-EXOMailbox -ResultSize 1 | Select-Object DisplayName, PrimarySmtpAddress Disconnect-ExchangeOnline -Confirm:$false
Import-Module Microsoft.Graph.Authentication -Force Import-Module PSPublishModule -Force $exo = Import-IsolatedModule -Profile ExchangeOnlineManagement -PassThru $exo | Format-List ProfileName, ModuleName, ContextName, IsolatedImportPath, WorkPath Connect-ExchangeOnline -ShowBanner:$false Get-EXOMailbox -ResultSize 1 | Select-Object DisplayName, PrimarySmtpAddress Disconnect-ExchangeOnline -Confirm:$false
Import-Module Microsoft.Graph.Authentication -Force Import-Module PSPublishModule -Force $teams = Import-IsolatedModule -Profile MicrosoftTeams -PassThru $teams | Format-List ProfileName, ModuleName, ContextName, IsolatedImportPath, WorkPath Connect-MicrosoftTeams Get-Team | Select-Object -First 5 DisplayName, GroupId, Visibility Disconnect-MicrosoftTeams
Import-Module Az.Accounts -Force Import-Module PSPublishModule -Force $teams = Import-IsolatedModule -Profile MicrosoftTeams -PassThru $teams | Format-List ProfileName, ModuleName, ContextName, IsolatedImportPath, WorkPath Connect-MicrosoftTeams Get-CsTenant | Select-Object DisplayName, TenantId Disconnect-MicrosoftTeams
Import-Module Az.Accounts -Force Import-Module Az.Storage -Force Import-Module Microsoft.Graph.Authentication -Force Import-Module PSPublishModule -Force $exo = Import-IsolatedModule -Profile ExchangeOnlineManagement -PassThru $teams = Import-IsolatedModule -Profile MicrosoftTeams -PassThru Connect-ExchangeOnline -ShowBanner:$false Get-EXOMailbox -ResultSize 1 | Select-Object DisplayName, PrimarySmtpAddress Connect-MicrosoftTeams Get-Team | Select-Object -First 5 DisplayName, GroupId, Visibility Disconnect-MicrosoftTeams Disconnect-ExchangeOnline -Confirm:$false
Reacted by Sam Erde and Daniel Chattan- added a commit that references this issue
on Jun 12, 2026 12Knocksinna commented
on Jun 23, 2026 ContributorMore actionsStill problems with Graph SDK V2.38 and Exchange Online Management 3.10. Have protested to the Exchange Online PowerShell team and whined at Gavin Barron (@gavinbarron).
https://office365itpros.com/2026/06/22/powershell-woes-and-cmdlets/
Reacted by Chris H and Sam ErdeReacted by yllekzReacted by yllekz12Knocksinna commented
on Jun 24, 2026 ContributorMore actionsRunning Connect-ExchangeOnline -DisableWAM allows Exchange to connect after a Graph connection is established. While you could argue that this fixes the problem, there are tons of customer production scripts in active use today that don't specify DisableWAM and that's the reason why the problem needs to be fixed.
Reacted by Maximilian Otter, Sam Erde, Suryendu Bhattacharyya and PimpJuiceIT12Knocksinna commented
on Jun 24, 2026 ContributorMore actionsThis works with PowerShell 5.1:
Import-Module Microsoft.Graph.Authentication -RequiredVersion 2.38.0
Import-Module ExchangeOnlineManagement -RequiredVersion 3.10.0
Connect-MgGraph
Connect-ExchangeOnlineAgain, it's just a workaround that might be acceptable for some but not for organizations that have to update production scripts or who have standardized on PowerShell Core.
Will this ever get fixed?
I had to fall back to ExchangeOnlineManagement 3.6.0 for now.Reacted by mark3grahamsI just released v1.0 of my DLL Pickle module that prevents most cases of these DLL version conflicts. Please try it out and let me know your results!
Install-Module -Name 'DLLPickle' -Scope CurrentUser
Import-Module -Name 'DLLPickle'
Import-DPLibrarythis works with zero drama. cheers 🍺
Reacted by Sam ErdeReacted by PimpJuiceITConfirming this is still present on the current latest: PowerShell 7.6.6, Microsoft.Graph.Authentication 2.40.0, ExchangeOnlineManagement 3.10.1. EXO-then-Graph gives the WithLogging method-not-found; Graph-then-EXO gives the RuntimeBroker NullReferenceException.
One refinement to the version-conflict framing above (e.g. Fabien Tschanz (@FabienTschanz)'s 8.15-vs-8.14 note): I traced the assembly binding, and matching the MSAL versions does not help. Both modules now ship the same Microsoft.Identity.Client (4.83.1) and the same native msalruntime, and it still fails. The break is cross-context type identity, not a version delta:
- EXO loads its MSAL and Microsoft.IdentityModel.Abstractions into the Default AssemblyLoadContext.
- msgraph-load-context has no Load override, so anything Graph does not load itself falls back to Default.
- Loading second, Graph's Azure.Identity binds to EXO's MSAL already resident in Default. That MSAL's WithLogging is typed to the IIdentityLogger from Default's Abstractions, while Azure.Identity passes the IIdentityLogger from its own context. Same type name, two ALCs, two identities, so the method will not bind.
The practical implication: even a release that perfectly aligned every MSAL version would still break as long as EXO populates Default and Graph falls back into it. More evidence for what gaelcolas (@gaelcolas) and Przemysław Kłys (@PrzemyslawKlys) already said, that EXO needs to load into its own ALC. Until then the isolation wrappers in this thread (DLLPickle, PSPublishModule's Import-IsolatedModule) are the only clean fixes; -DisableWAM sidesteps the Graph-first NullReferenceException but not the WithLogging clash.
Reacted by Sam ErdeConfirming this is still present on the current latest: PowerShell 7.6.6, Microsoft.Graph.Authentication 2.40.0, ExchangeOnlineManagement 3.10.1. EXO-then-Graph gives the WithLogging method-not-found; Graph-then-EXO gives the RuntimeBroker NullReferenceException.
One refinement to the version-conflict framing above (e.g. Fabien Tschanz (@FabienTschanz)'s 8.15-vs-8.14 note): I traced the assembly binding, and matching the MSAL versions does not help. Both modules now ship the same Microsoft.Identity.Client (4.83.1) and the same native msalruntime, and it still fails. The break is cross-context type identity, not a version delta:
- EXO loads its MSAL and Microsoft.IdentityModel.Abstractions into the Default AssemblyLoadContext.
- msgraph-load-context has no Load override, so anything Graph does not load itself falls back to Default.
- Loading second, Graph's Azure.Identity binds to EXO's MSAL already resident in Default. That MSAL's WithLogging is typed to the IIdentityLogger from Default's Abstractions, while Azure.Identity passes the IIdentityLogger from its own context. Same type name, two ALCs, two identities, so the method will not bind.
The practical implication: even a release that perfectly aligned every MSAL version would still break as long as EXO populates Default and Graph falls back into it. More evidence for what gaelcolas (@gaelcolas) and Przemysław Kłys (@PrzemyslawKlys) already said, that EXO needs to load into its own ALC. Until then the isolation wrappers in this thread (DLLPickle, PSPublishModule's Import-IsolatedModule) are the only clean fixes; -DisableWAM sidesteps the Graph-first NullReferenceException but not the WithLogging clash.
Nice summary. Do you have an agent skill that checks to see if open issues are still relevant or have any potential new resolutions?
No, that was a one-off as a result of trying to work through the mechanics
Reacted by Sam ErdeOn Sep 21 I said the clean fix was EXO loading into its own ALC. #3789 (merged Sep 23; no release contains it yet, v2.40.0 predates the merge) takes the other route: Graph isolates itself. It replaces msgraph-load-context, which had no Load override and fell back to Default, with a GraphAssemblyLoadContext that overrides Load and resolves MSAL, Azure.Identity and Microsoft.IdentityModel.Abstractions from Graph's own folder. Only Microsoft.Graph.Authentication.Core is bridged into Default, and the old AppDomain.AssemblyResolve handler is no longer registered on PS7. Graph can therefore no longer bind to EXO's MSAL in Default, so the WithLogging failure in this issue (EXO-then-Graph) should be gone by construction, and that no longer depends on which MSAL EXO ships (the concern in the Dec 18 comment).
Two caveats. The PR's test pre-loads a stub Microsoft.Identity.Client and connects with -AccessToken, so it verifies the load contexts, not WAM or the WithLogging path. And nothing in the PR exercises Graph-then-EXO (the RuntimeBroker NullReferenceException reported from Feb onward); that direction needs a test build. Windows PowerShell 5.1 keeps the AssemblyResolve approach and is not covered.
Maintainers: worth linking #3789 here alongside #3576, and keeping this open until a release confirms both directions.
Mike Crowley (@Mike-Crowley) eventually it is better if all modules that have dependencies upon Microsoft.Identity.Client (Msal) use a loader principle that looks the same.
Mike Crowley (@Mike-Crowley) eventually it is better if all modules that have dependencies upon Microsoft.Identity.Client (Msal) use a loader principle that looks the same.
If only. The Exchange team run by their own rules with regard to PowerShell, from everything I've seen over the last 17+ years.
I built a small harness for this: one fresh pwsh per scenario, a load-state snapshot after every step. PowerShell 7.6.6, Microsoft.Graph.Authentication 2.40.0, ExchangeOnlineManagement 3.10.1, seven scenarios.
Observed, Graph-then-EXO:
- Importing Graph alone is fine. Any Graph WAM sign-in first breaks EXO, even a silent one with no picker.
- After the failure two msalruntime.dll files are mapped (Graph's from Dependencies, EXO's from netCore\runtimes\win-x64\native); a bare-name lookup returns Graph's.
- Both NativeInterop copies declare all 269 P/Invokes by bare name ("msalruntime" on x64); neither registers a DllImportResolver.
- EXO's RuntimeBroker after the failure (read by reflection): lazy Core null, s_initException MsalRuntimeException, ApiContractViolation, "Authenticator Factory has already been started"; Graph's copy has a live Core. The NRE is that null being dereferenced.
- EXO's managed stack sits in Default from netCore; Graph's AssemblyResolve handler answered none of its requests. This direction is native.
EXO-then-Graph still fails (WithLogging MissingMethodException), so neither order works. Two same-session combinations connected: Graph, then Connect-ExchangeOnline -DisableWAM; or Graph via -AccessToken (token from Az.Accounts), then EXO as normal, because Graph never starts msalruntime.
Predictions, no build yet: #3789 fixes EXO-then-Graph by construction; Graph-then-EXO survives it, since EXO's bare-name P/Invokes still find Graph's started copy. Untested fixes: NativeInterop pins P/Invokes to its preloaded handle or tolerates a second startup; Graph uses a Graph-only file name; EXO gets its own load context or DllImportResolver. Related: #3576.
Ask: can the NativeInterop part be routed to the MSAL owners, or should I file it in MSAL.NET?
Harness and report: https://github.com/Mike-Crowley/graph-exo-loadorder
Microsoft's post today, Action Required: Upgrade ExchangeOnlineManagement PowerShell Module to Version 3.10.1 or Newer, puts an end date on the "stay on an old EXO" workaround: from 31 March 2027, interactive non-WAM sign-in on versions before 3.10.1 may fail. Their FAQ says WAM is not being required, so Graph first, then Connect-ExchangeOnline -DisableWAM (works today on 3.10.1) is not what they are retiring. The path they are hardening is the WAM one, and that is the path this issue breaks.
Describe the bug
I don't know, if this is related to the ExchangeOnlineManagement module (my suspicison) or to Microsoft.Graph, but you should know; too, I guess:
I updated Microsoft.Graph from 2.29.1. to 2.30.0 yesterday and ExchangeOnlineManagement from 3.8.0 to 3.9.0. After the update I found that when I run Connect-ExchangeOnline before Connect-MgGraph, the latter fails with the following error:
When I run Connect-MgGraph first and then Connect-ExchangeOnline, it works.
Expected behavior
IMO it should not matter, which command is run first.
How to reproduce
SDK Version
2.30.0
Latest version known to work for scenario above?
2.29.1 together with ExchangeOnlineManagement 3.8.0
Known Workarounds
Debug output
Click to expand log
```DEBUG: ClientCertificateCredential.GetToken invoked. Scopes: [ https://graph.microsoft.com/.default ] ParentRequestId:
DEBUG: ClientCertificateCredential.GetToken was unable to retrieve an access token. Scopes: [ https://graph.microsoft.com/.default ] ParentRequestId: Exception: Azure.Identity.AuthenticationFailedException (0x80131500): ClientCertificateCredential authentication failed: Method not found: '!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder
1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'. ---> System.MissingMethodException (0x80131513): Method not found: '!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'.Connect-MgGraph: ClientCertificateCredential authentication failed: Method not found: '!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'.
Name Value
PSVersion 7.5.2
PSEdition Core
GitCommitId 7.5.2
OS Microsoft Windows 10.0.26100
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0