Skip to content

Connect-MgGraph fails after Connect-ExchangeOnline #3394

Open

Description

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:

Connect-MgGraph: ClientCertificateCredential authentication failed: Method not found: '!0 Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'.

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

  • On Powershell 7.5.2 ...
  • Install Microsoft.Graph 2.30.0
  • Install ExchangeOnlineManagement 3.9.0
  • First run Connect-ExchangeOnline. ( I used certificate authentication )
  • Second run Connect-MgGraph. It does not matter if user or certificate authentication. I tried both
  • You should get the error described above

SDK Version

2.30.0

Latest version known to work for scenario above?

2.29.1 together with ExchangeOnlineManagement 3.8.0

Known Workarounds

  1. First run Connect-MgGraph
  2. Then run Connect-ExchangeOnline

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.BaseAbstractApplicationBuilder1.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)'.

</details>


### Configuration

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

Architecture: x64

### Other information

_No response_

Activity

  1. SteviebabesUK commented on Feb 13, 2026

    @SteviebabesUK

    Steve Lee (@SteveL-MSFT) Fascinating read!
    What I think those of us out in the field doing basic O365 user management on a day to day basis is for you guys to bang your heads together and stop this happening on an alarmingly regular basis for all of the key modules i.e. MGGraph, ExchangeOnline, PnP & Sharepoint.

  2. FabienTschanz commented on Mar 5, 2026

    @FabienTschanz
    Contributor

    And just found that there is another incompatibility with Microsoft Graph 2.35.1 and MicrosoftTeams 7.6.0. Doesn't matter which module is loaded first, if MicrosoftTeams is loaded, then Connect-MgGraph will fail:

    ❯ Import-Module Microsoft.Graph.Authentication
    ❯ Import-Module MicrosoftTeams
    ❯ init # My wrapper function around Connect-MgGraph for easy initialization
    Connect-MgGraph: C:\Users\...\Documents\PowerShell\Microsoft.PowerShell_profile.ps1:64
    Line |
      64 |      Connect-MgGraph -ApplicationId $clientId -TenantId $tenantIdName  …
         |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         | ClientCertificateCredential authentication failed: Method not found: '!0
         | Microsoft.Identity.Client.BaseAbstractApplicationBuilder`1.WithLogging(Microsoft.IdentityModel.Abstractions.IIdentityLogger, Boolean)'.

    The issue is with the Microsoft.IdentityModel.Abstractions.dll, where Microsoft.Graph.Authentication uses 8.15.0.61118 and MicrosoftTeams uses 8.14.0.60815.

    [appdomain]::currentdomain.GetAssemblies() | Where-Object Location -Like *identitymodel.abstractions*                                                                                                                                                                                                                                                                                            
    
    GAC    Version        Location
    ---    -------        --------
    False  v4.0.30319     C:\Program Files\WindowsPowerShell\Modules\Microsoft.Graph.Authentication\2.35.1\Dependencies\Microsoft.IdentityModel.Abstractions.dll
    False  v4.0.30319     C:\Program Files\WindowsPowerShell\Modules\MicrosoftTeams\7.6.0\netcoreapp3.1\Microsoft.IdentityModel.Abstractions.dll

    How are we supposed to have a functioning environment if it only takes one single module to be update for nothing to work at the end? It's so frustrating, especially when we PowerShell module authors require several of those Graph, Exchange or Teams modules to be present for our work (looking at you M365DSC). I guess the only way for us to keep working is to spawn a new PowerShell job each time a new module is going to be loaded... Please do something about that.

  3. SamErde commented on Mar 12, 2026

    @SamErde
    Contributor

    I 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-DPLibrary
  4. marleyhehe commented on Apr 2, 2026

    @marleyhehe

    Still a issue. :@

  5. PimpJuiceIT commented on Apr 4, 2026

    @PimpJuiceIT

    Still a issue. :@

    I’m encountering the issue still, even after installing and loading the DLLPickle module.

    Here's the detail list of the environment I'm working with:

    • PowerShell Version: 7.6.0
    • Microsoft.Graph Module: 2.36.1
    • ExchangeOnlineManagement Module: 3.9.2
    • Windows 11 Enterprise 25H2 (26200.7462)

    Priming and connecting to Exchange Online before connecting to Microsoft Graph helps resolve the issue. Currently, I'm testing a V2 script with that as a workaround to get in some of the repetitions on account provisioning operations before updating my main system.

  6. Borgquite commented on Apr 14, 2026

    @Borgquite

    Fabien Tschanz (@FabienTschanz) I found that when using Windows PowerShell 5.1, ExchangeOnlineManagement plays marginally better with Microsoft.Graph.* 2.36.1 if you downgrade to 3.9.0 instead of 3.9.2, at least in Azure Automation.

    Also connect to Exchange Online before Microsoft Graph.

    As far as I can see ExchangeOnlineManagement 3.9.2 doesn't appear to include any critical used by Microsoft365DSC so it could be worth downgrading. I wouldn't upgrade the modules until something critical is needed, or Microsoft actually finally resolve this.

  7. PrzemyslawKlys commented on Jun 3, 2026

    @PrzemyslawKlys

    While we wait for MS to fix it I've added ALC automated handling to my PowerShell builder Install-Module PSPublishModule

    Import-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
    Image

    This one proves it works also with DllPickle if that's your choice, but it shouldn't be nessecary

    Image
    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
  8. 12Knocksinna commented on Jun 23, 2026

    @12Knocksinna
    Contributor

    Still 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/

  9. 12Knocksinna commented on Jun 24, 2026

    @12Knocksinna
    Contributor

    Running 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.

  10. 12Knocksinna commented on Jun 24, 2026

    @12Knocksinna
    Contributor

    This works with PowerShell 5.1:

    Import-Module Microsoft.Graph.Authentication -RequiredVersion 2.38.0
    Import-Module ExchangeOnlineManagement -RequiredVersion 3.10.0
    Connect-MgGraph
    Connect-ExchangeOnline

    Again, 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.

  11. tymondouglas commented on Jul 27, 2026

    @tymondouglas

    Will this ever get fixed?
    I had to fall back to ExchangeOnlineManagement 3.6.0 for now.

  12. imbaru-design commented on Aug 26, 2026

    @imbaru-design

    I 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-DPLibrary

    this works with zero drama. cheers 🍺

  13. Mike-Crowley commented on Sep 21, 2026

    @Mike-Crowley

    Confirming 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.

  14. SamErde commented on Sep 21, 2026

    @SamErde
    Contributor

    Confirming 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?

  15. Mike-Crowley commented on Sep 21, 2026

    @Mike-Crowley

    No, that was a one-off as a result of trying to work through the mechanics

  16. Mike-Crowley commented on Sep 25, 2026

    @Mike-Crowley

    On 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.

  17. svrooij commented on Sep 25, 2026

    @svrooij
    Contributor

    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.

  18. robinmalik commented on Sep 25, 2026

    @robinmalik

    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.

  19. Mike-Crowley commented on Sep 25, 2026

    @Mike-Crowley

    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

  20. Mike-Crowley commented on Oct 1, 2026

    @Mike-Crowley

    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.

  21. Mike-Crowley commented on Oct 19, 2026

    @Mike-Crowley

    Re-ran the harness on the released 2.41.2 (PowerShell 7.6.7, ExchangeOnlineManagement 3.10.1, same nine scenarios, one fresh pwsh each). Every order now connects, including Graph-then-EXO.

    • EXO-then-Graph: fixed as predicted. Microsoft.Identity.Client is loaded twice (EXO's 4.83.1 in Default, Graph's 4.90.0 in the new Microsoft.Graph.Authentication load context), so the WithLogging binding never happens.
    • Graph-then-EXO: my prediction that it would survive the PR was wrong, though not for the reason I would have guessed. The native picture is unchanged from 2.40.0: two msalruntime.dll copies mapped, a bare-name lookup still returns Graph's, EXO's NativeInterop 0.19.4 still P/Invokes by bare name with no DllImportResolver. What changed is that EXO's second startup against Graph's copy is now accepted: EXO's RuntimeBroker ends with a live Core and no s_initException, where 2.40.0 recorded ApiContractViolation "Authenticator Factory has already been started". The isolation changed the managed side only; on the native side the difference is the runtime Graph now ships (NativeInterop 0.20.6 with MSAL 4.90.0, versus 0.19.4 in Graph 2.40.0 and still in EXO 3.10.1). I did not trace whether that is msalruntime itself or how MSAL 4.90 starts it.
    • Also connected: graph-cancel-then-exo (WAM again signed in silently), -DisableWAM, and Graph via -AccessToken then EXO.

    One caveat, reasoning rather than observation: EXO's bare-name binding still decides which runtime EXO runs on after a Graph sign-in. Today that copy is newer than EXO's own; the day EXO ships a newer NativeInterop than Graph, Graph-first puts EXO's interop on an older runtime again. The NativeInterop ask from my earlier comment (pin P/Invokes to the preloaded handle) still looks like the durable fix.

    Full report: https://github.com/Mike-Crowley/graph-exo-loadorder/blob/main/report-2.41.2.md

    🤖 Claude Mythos 5.1 (max effort) via Claude Code

  22. svrooij commented on Oct 21, 2026

    @svrooij
    Contributor

    The way the AssemblyLoadContext is implemented does not provide a way to load multiple copies of Native binaries. The culprit, the msal broker, is designed to create a singleton that is reachable over a named pipe. And there can only be one running on the machine. If you were to load multiple on the same machine they will fight to respond to that named pipe.

    What if we fix this issue #3806 and then migrate all the other modules to call the new Get-MgAccessToken -Scope ... command. Then all the external dependencies to the broker can be removed?

    Other solution is to always keep the versions equal, but that would require some advanced dependency management combined with synchronized release cycles

  23. Mike-Crowley commented on Oct 21, 2026

    @Mike-Crowley

    Thanks. Here is what the Oct 19 snapshots show on the two testable parts, with observed and inferred kept apart; one machine, one run per scenario, details in report-2.41.2.md.

    • Two native copies in one process: in both orders on 2.41.2 the final snapshot has two msalruntime.dll files mapped, Graph's from Dependencies\ and EXO's from netCore\runtimes\win-x64\native. In EXO-then-Graph, EXO's copy appears at connect-exo and Graph's at connect-graph, and afterwards both RuntimeBroker copies have a created, non-null Core and no s_initException (exo-then-graph, "RuntimeBroker statics"). Read the way RuntimeBroker's 4.83.1 source works, each copy's Startup succeeded. "Each on its own copy" is inferred from .NET's P/Invoke resolution for an assembly in a custom ALC (LoadUnmanagedDll is consulted first), not traced, and I have not read the 4.90 source.
    • The "already started" rejection was on the same mapped copy, not across copies: on 2.40.0, with both modules on NativeInterop 0.19.4, EXO's startup landed on Graph's already-started copy through bare-name binding and was rejected (ApiContractViolation "Authenticator Factory has already been started"); on 2.41.2 the same binding puts EXO on Graph's 0.20.6 copy and the second startup succeeded. Whether that is the runtime or MSAL 4.90's startup call, I cannot tell from outside.
    • Limits: both sign-ins completed with two started copies, and the harness stops there. If two copies conflict later, as the named-pipe singleton you describe would predict, nothing in these runs would have seen it. I do not know msalruntime's internals, so I cannot speak to that part.

    On Get-MgAccessToken: Connect-ExchangeOnline has taken an external token since 3.1.0 (-AccessToken), so the route exists in principle. What I do not know is whether the Graph PowerShell client can be issued a token for the Exchange resource at all, and in any case it would cover scripts that opt in, while the default interactive path would still start EXO's own broker, which is where this issue lives. On keeping versions equal: 2.40.0 and EXO 3.10.1 already shared NativeInterop 0.19.4 and MSAL 4.83.1 and still collided, so equal versions are not sufficient on their own; the copy mapped first also has to accept a second startup. That is why a DllImportResolver that pins each module's P/Invokes to the copy it preloaded, in NativeInterop or in EXO, still looks to me like the change that does not depend on anyone's release calendar. If two started copies truly cannot coexist, that moves the fix to MSAL, and the two-live-copies observation above is the one data point I have against it.

    🤖 Claude Mythos 5.1 (max effort) via Claude Code

  24. svrooij commented on Oct 21, 2026

    @svrooij
    Contributor

    Mike Crowley (@Mike-Crowley) the claude stuff does not really help. I have no clue what the issue is. Maybe I'm just a bit tired at the moment but from what I'm reading PowerShell assembly resolving does not handle native assemblies the same way as managed assemblies. That begs the question, why is this even built in native code 😉 (different team maybe)

  25. Mike-Crowley commented on Oct 21, 2026

    @Mike-Crowley

    Hey Stephan, sorry about that. I was using Claude to be comprehensive, since I'm sure Microsoft will be using AI as well to read and ingest this work. Here is my understanding, and what I'm proposing:

    Your ALC fixed the .NET side. EXO-first works now on 2.41.2. What's left is msalruntime.dll, which is a native DLL, so the ALC doesn't cover it. Graph and EXO each ship their own copy, but Windows finds native DLLs by name. So whoever signs in first, the other module ends up using that first copy. On 2.40 that crashed. On 2.41.2 it still happens, but Graph's newer copy doesn't mind being started twice, so it works. That's luck, not a fix. If EXO ever ships a newer msalruntime than Graph, it could break again.

    My proposal: each module should point its msalruntime calls at its own copy. Your ALC already does that for Graph (LoadUnmanagedDll). EXO doesn't. If EXO did the same, or if MSAL's NativeInterop package did it for everyone, load order wouldn't matter anymore. Get-MgAccessToken is still a good idea, but it only helps people who pass a token to EXO. Normal EXO sign-in would still start its own msalruntime.

  26. svrooij commented on Oct 21, 2026

    @svrooij
    Contributor

    I want the EXO team to remove the broker completely and make Microsoft.Graph.Authentication the only module that ships the msalclient.

    Then the exo team can make a dependency upon this module and just call into the Get-MgAccessToken command under the covers

    Connect-MgGraph .....
    Connect-ExchangeOnline # => Calls Get-MgAccessToken -Scopes "https://outlook.office.com/.default" under the covers

    Maybe that last command can even be removed, and every call to exchange would just try to get a token (which will auto cache and refresh if needed)

  27. Mike-Crowley commented on Oct 21, 2026

    @Mike-Crowley

    I'd like to live in that utopia! But that means SharePoint, Teams, Azure, etc would all need to change their approach, and this multi-decade-old Microsoft org chart meme gives us an idea how that might go: https://assets.sbnation.com/assets/2907963/microsoftguns.jpg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:bugA broken experience

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions