entra-powershell icon indicating copy to clipboard operation
entra-powershell copied to clipboard

Get-EntraContext is very slow when you are not authenticated

Open alexandair opened this issue 1 year ago • 20 comments

Open new PowerShell session and run Get-EntraContext. It runs sometimes for more than 60 seconds. Get-MgContext runs for less than a second.

PS> get-mgcontext
PS> get-entracontext
PS> h

  Id     Duration CommandLine
  --     -------- -----------
   1        0.724 get-mgcontext
   2     1:02.088 get-entracontext

alexandair avatar Jul 05 '24 10:07 alexandair

This is the same issue as #287 (first execution of Entra command is extremely slow) and #437 (finding Entra commands with Get-Command is extremely slow). All of the 'requiredModules' are being imported for the first run, and then every subsequent run is fast.

SamErde avatar Jul 05 '24 13:07 SamErde

And, surprisingly 😀, all three are open by me.

Slow Get-EntraContext is especially critical, because that's the one people use in scripts to check if they are authenticated or not.

alexandair avatar Jul 05 '24 14:07 alexandair

While it may seem redundant, I'm glad to see all three issues opened because it helps to highlight how broadly the design affects use of the module in numerous ways. I hope my comment didn't sound like I was dismissing the issue in any way!

SamErde avatar Jul 05 '24 14:07 SamErde

@alexandair , we have an internal work item tracking this item (We wanted to release the module to public preview first). It has been prioritized for the quarter starting July 2024.

SteveMutungi254 avatar Jul 05 '24 17:07 SteveMutungi254

I will be tagging the "expected" release milestone on GitHub too to close the loop.

SteveMutungi254 avatar Jul 05 '24 17:07 SteveMutungi254

@alexandair: We have been investigating this issue.

Initial work has already been merged, and you should notice some improvements with the 0.15.0-preview release. Please let us know if you've seen any performance improvements.

More optimization work is coming soon.

SteveMutungi254 avatar Sep 15 '24 17:09 SteveMutungi254

@SteveMutungi254

I use 0.15.0-preview. I don't see a significant performance improvement for the first execution of Get-EntraContext.

PS C:\> get-mgcontext
PS C:\> get-mgcontext
PS C:\> h

  Id     Duration CommandLine
  --     -------- -----------
   1        0.654 get-mgcontext
   2        0.005 get-mgcontext
PS C:\> get-entracontext
PS C:\> get-entracontext
PS C:\> h

  Id     Duration CommandLine
  --     -------- -----------
   1       54.265 get-entracontext
   2        0.002 get-entracontext

alexandair avatar Sep 15 '24 17:09 alexandair

@alexandair: Do you do this while having the module already imported? Because importing the module takes ages on my machine (around 1 minute), so MAYBE it is caused by the fact that by the first execution, the module will be imported first!

HCRitter avatar Sep 25 '24 08:09 HCRitter

@HCRitter I am doing it before the modules are loaded. That's exactly the reason why it runs slowly. Entra PowerShell team is trying to improve the performance and load modules faster.

alexandair avatar Sep 25 '24 12:09 alexandair

@alexandair @SteveMutungi254

I've been investigating the underlying issue and have made some progress, although I haven't pinpointed the exact cause yet.

After some testing, I found that importing the module directly from the .psm1 file on the local drive loads incredibly fast. However, when switching to the .psd1 file, it takes about 30-60 seconds on my machine. Digging deeper, I discovered that removing the RequiredModules section from the .psd1 file significantly reduces the load time, bringing it down to under 1 second.

Here’s the relevant section of the .psd1:

RequiredModules = @(@{ModuleName = 'Microsoft.Graph.Users'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Users.Actions'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Users.Functions'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Groups'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Identity.DirectoryManagement'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Identity.Governance'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Identity.SignIns'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Applications'; RequiredVersion = '2.15.0'; }, 
               @{ModuleName = 'Microsoft.Graph.Reports'; RequiredVersion = '2.15.0'; })

Although this doesn't fully resolve the issue, it narrows it down. The slow loading time seems to be related to the handling of RequiredModules in the .psd1 file.

I'll continue to investigate further and keep you posted.

HCRitter avatar Sep 25 '24 14:09 HCRitter

The issue with the Microsoft.Graph.Entra module is that it's not just checking whether the required modules are installed — it’s also importing them. When all the modules are imported together, it significantly increases load time. If you try importing them manually, you'll notice the same slow behavior.

It might make more sense to only check and import the modules when they’re actually needed. For example, if I only need the Microsoft.Graph.Users module in my current session, there’s no reason to load Microsoft.Graph.Applications or other unnecessary modules.

While importing everything upfront may be considered best practice, from a user experience perspective, or as a temporary workaround, shifting the module checks and imports to the execution of specific functions could help. This approach would reduce the initial load time and prevent unnecessary modules from bloating the current session.

HCRitter avatar Sep 25 '24 14:09 HCRitter

That's what we have also found and noted in several related issues. Thanks for adding some extra detail!

SamErde avatar Sep 25 '24 15:09 SamErde

@SamErde @alexandair @HCRitter Entra PowerShell cmdlets have a dependency on the Microsoft Graph PowerShell modules. The RequiredModules = @() are critical to ensure all dependent modules are installed when installing Entra PowerShell. This achieves 2 things

  1. Removes the burden of figuring out which specific Graph PowerShell module must be installed.
  2. Ensures we install the correct version of Graph PowerShell modules to avoid dependent Graph PowerShell modules which may have regressions.

This has its drawbacks as well and the major one is the poor performance on executing Entra PowerShell commands for the first time.

We are looking at finding a middle-ground where we still have the dependent modules installed and have better performance on first command execution. This is still work in progress and we will keep you informed. Thanks for the investigations. It helps us move closer to a solution.

KenitoInc avatar Sep 26 '24 07:09 KenitoInc

@KenitoInc @SteveMutungi254 @SamErde @HCRitter

Entra PowerShell might not be as big as Microsoft Graph PowerShell SDK or Azure PowerShell, but needs to deal with the performance problem of loading the required modules in the same way. That means you need to redesign Entra PowerShell.

First, Entra PowerShell should stop being "advertise" as a part of the Microsoft.Graph module, because that's simply not true. Microsoft.Graph is auto-generated, and Entra PowerShell is not. Therefore, Entra PowerShell module needs new name -- Microsoft.Entra (you will see soon why is that important and not just a cosmetic change).

New Microsoft.Entra should be then an umbrella module, just like Microsoft.Graph and Az modules, and take care of installing all sub-modules (if you want all of them) and also of installing all required modules.

Sub-modules will be:

Microsoft.Entra.Users
Microsoft.Entra.Groups
Microsoft.Entra.Applications
....

The result of this kind of design will be much faster first execution of the Entra commands and much faster Get-Command <EntraCommand>, because the system won't load all required modules. For example, if we want to run Get-EntraUser, only the following modules will need to be loaded:

Microsoft.Graph.Authentication
Microsoft.Graph.Users
Microsoft.Entra.Users

This will also allow users of, for example, Azure Functions, Azure Automation, GitHub Actions, and Azure Pipelines, to have faster execution because if they work only with Entra users and groups, they will need a much smaller number of Entra sub-modules and required Microsoft.Graph.* modules.

All of this also applies to Entra PowerShell Beta module.

alexandair avatar Sep 26 '24 10:09 alexandair

@alexandair Your suggestion is valid. This is something that will guide v2 breaking change release

KenitoInc avatar Oct 07 '24 08:10 KenitoInc

@KenitoInc Preview release is the right time for breaking changes. Performance issue should be fixed before v1 GA. Not a single user would like to wait for a minute to see the results of the first Entra PowerShell command.

alexandair avatar Oct 07 '24 21:10 alexandair

I would respectfully suggest that @alexandair is correct in this. Even though it may mean a delay in the GA release timeframe, it will provide a FAR better initial experience for customers. First impressions matter. 😀🙏🏻

SamErde avatar Oct 08 '24 01:10 SamErde

Hi, @alexandair, @HCRitter, @SamErde,

We are pleased to announce the successful implementation of modularization in Entra PowerShell. We sincerely appreciate the time you took to help us investigate, troubleshoot, and contribute. Your support means the world to us.

The improvements are available from version 0.22.0 onwards. We have also finalized the update to our Entra PowerShell public Learn documentation with these changes.

PS: I'll wait one to two weeks before closing this issue. Tagging you for your awareness.

cc: @KenitoInc, @emmanuel-karanja

SteveMutungi254 avatar Jan 23 '25 12:01 SteveMutungi254

Thanks, @SteveMutungi254. The team did a massive amount of work to get here, and it shows!

The Graph module dependencies still take some time to load, and this affects Import-Module Microsft.Entra, but there's not much you can do about that without bypassing those completely to write native Graph requests. However, using Get-Command now provides immediate results without having to import the module! The one caveat is that we must use Get-Command -Module Microsoft.Entra* because no commands are exported from the base Microsoft.Entra module.

 SamErde on  C:/Code 
# Get-Module -ListAvailable -Refresh -Name Microsoft.Entra* | Format-Table Name, RequiredModules

Write-Host ("{0} seconds:`tList commands with '`Get-Command -Module Microsoft.Entra.*' `n" -f [math]::Round( (Measure-Command {
    Get-Command -Module Microsoft.Entra.*
} ).TotalSeconds, 2))

@('Applications', 'Authentication', 'DirectoryManagement', 'Governance', 'Groups', 'Reports', 'SignIns', 'Users') | ForEach-Object {
    Write-Host ("{0} seconds:`tMicrosoft.Entra.$_" -f [math]::Round((Measure-Command {
        Import-Module -Name "Microsoft.Entra.$_"
    }).TotalSeconds), 2)
}


Name                                RequiredModules
----                                ---------------
Microsoft.Entra                     {Microsoft.Entra.Applications, Microsoft.Entra.Authentication, Microsoft.Entra.DirectoryManagement, Microsoft.E… 
Microsoft.Entra.Applications        {Microsoft.Graph.Applications}
Microsoft.Entra.Authentication      {Microsoft.Graph.Authentication}
Microsoft.Entra.DirectoryManagement {Microsoft.Graph.Identity.DirectoryManagement}
Microsoft.Entra.Governance          {Microsoft.Graph.Identity.Governance}
Microsoft.Entra.Groups              {Microsoft.Graph.Groups}
Microsoft.Entra.Reports             {Microsoft.Graph.Reports}
Microsoft.Entra.SignIns             {Microsoft.Graph.Identity.SignIns}
Microsoft.Entra.Users               {Microsoft.Graph.Users, Microsoft.Graph.Users.Actions, Microsoft.Graph.Users.Functions}

0.06 seconds:   List commands with 'Get-Command -Module Microsoft.Entra.*' 

6 seconds:      Microsoft.Entra.Applications
0 seconds:      Microsoft.Entra.Authentication
4 seconds:      Microsoft.Entra.DirectoryManagement
8 seconds:      Microsoft.Entra.Governance
5 seconds:      Microsoft.Entra.Groups
3 seconds:      Microsoft.Entra.Reports
5 seconds:      Microsoft.Entra.SignIns
12 seconds:     Microsoft.Entra.Users
 SamErde on  C:/Code 
#

SamErde avatar Jan 23 '25 19:01 SamErde

Original issue is fixed. Get-EntraContext is now just slightly slower than Get-MgContext.

alexandair avatar Jan 23 '25 22:01 alexandair