Preview of New Entra PowerShell Module Built on the Microsoft Graph

On June 27, 2024, Microsoft announced the public preview of the Microsoft Entra PowerShell module. The new module is intended to ease the migration of customers who still have scripts running cmdlets from the AzureAD and AzureAD Preview modules that Microsoft deprecated on March 30, 2024. Microsoft says that these modules will function until March 30, 2025, and will then be retired, so obviously time is running out.

Then again, time has been running out for these modules since Microsoft first announced their intention to move away from the Azure Graph to embrace the Microsoft Graph as the foundation for Azure AD (Entra ID) PowerShell in June 2020. I guess it takes some organizations a long time to migrate.

Microsoft says that the new module is “high quality.” Let’s hope that this is so because the Entra PowerShell module is built on top of the Microsoft Graph PowerShell SDK, which has had a sorry history of quality failures recently.

Why Two Modules?

When I first heard about the Entra PowerShell module a few months ago, my initial reaction was that the existence of the module would confuse customers. We have spent the last few years convincing people about the wisdom of embracing the Microsoft Graph. Even if there have been a few bumps along the way, we’ve encouraged people to rewrite scripts and replace old AzureAD and MSOL cmdlets with Microsoft Graph PowerShell SDK cmdlets.

Let me be clear on this point: if you’ve taken our advice and moved to the Microsoft Graph PowerShell SDK, you have nothing more to do. The Entra PowerShell module is for organizations who haven’t transitioned from the old AzureAD modules. It is a solution that allows the old cmdlets to run “with minimal modifications.” What this means is that the Entra PowerShell module includes the EntraAzureADAlias cmdlet. When used in a session, the EntraAzureADAlias cmdlet enables aliases for common AzureAD cmdlets like Get-AzureADUser and Get-AzureADGroup.

Providing an alias to translate old AzureAD cmdlet names to Entra cmdlet names is nice and it mostly works. There’s no support for cmdlets from the Microsoft Services Online (MSOL) module, like Get-MsolUser.

Even though aliasing allows commands using AzureAD cmdlets to run, the Entra module is not a silver bullet for migration. Not all commands run without intervention and because Graph authentication and permissions underpin the module, there’s a bunch of work to do to make sure that scripts run without a hitch.

Installing the Entra PowerShell Module

The Entra PowerShell module depends on many of the modules distributed with the Microsoft Graph PowerShell SDK, including the Microsoft.Graph.Authentication module which handles connections. Before attempting to install the Entra module, start a new PowerShell session to remove the possibility of conflicts between the Graph modules distributed with the Entra module. Then install the V1.0 and beta modules from the PowerShell gallery:

Install-Module Microsoft.Graph.Entra -AllowPrerelease -Repository PSGallery -Force
Install-Module Microsoft.Graph.Entra.Beta -AllowPrerelease -Repository PSGallery -Force

The Microsoft Graph PowerShell SDK split into V1.0 (production) and beta modules for its V2.0 release, and that’s why the Entra module uses the same structure. You only need to install the beta module if you intend to use beta cmdlets. The problem is that it’s difficult to predict when that need might arise, so it’s safer to install the two.

If the PowerShell installer complains that it can’t install a module because some cmdlets already exist on the system, add the AllowClobber parameter (which is what I had to do).

Connecting with the Entra PowerShell Module

To start an Entra PowerShell session, use the Connect-Entra cmdlet in the same way as the Connect-MgGraph cmdlet functions for the Microsoft Graph PowerShell SDK. As it turns out, Connect-Entra is an alias for Connect-MgGraph and exists purely to give the appearance that the new module has its own connect cmdlet:

Import-Module Microsoft.Graph.Entra
Connect-Entra -NoWelcome -Scopes User.Read.All

Immediately, the dependency on Graph APIs and permissions is obvious. In the FAQ for the announcement, Microsoft says that the Entra PowerShell module is not a “pre-consented app” or “preauthorized.” When someone runs the Connect-AzureAD cmdlet to create a session with the AzureAD module, the permissions associated with any roles held by their account are available. The situation is very different with the Graph.

For example, an administrator needs no further permission before they can run the Get-AzureADGroup or Get-AzureADUser cmdlets to manage tenants’ users or groups. But the same operations performed via Graph APIs require explicit consent for permissions like User.Read.All or Group.Read.All. Permissions can be gained by seeking consent for specific scopes when signing into an interactive session or through the administrative roles held by the signed in user. However, because interactive sessions use delegated permissions, some data that’s only accessible through application (app-only) permissions will remain inaccessible.

Application permissions should not be a problem in the context of migrating AzureAD cmdlets to Entra cmdlets because most people using interactive Entra sessions will be administrators and anyway, AzureAD cmdlets don’t interact with Microsoft 365 data that require application permissions, like mailboxes or sites. If you want to use application permissions with the Entra PowerShell module, create an Entra app registration, assign the necessary application permissions to the app, and use a certificate or certificate thumprint loaded into the app to authenticate.

Running AzureAD Cmdlets

I don’t have any scripts based on the AzureAD module that are now in use. Everything has been converted to the Microsoft Graph PowerShell SDK. This meant that I had to look back at some old articles to find test cases to see how well the Entra PowerShell module copied with old code. Here are two examples:

Find all member accounts in a tenant:

Enable-EntraAzureADAlias
$Users = Get-AzureADUser -All $True -Filter "Usertype eq 'Member'"
Get-EntraUser: A positional parameter cannot be found that accepts argument 'True'.

Microsoft claims “over 98% compatibility” for the Entra module with AzureAD cmdlets. I guess I was unlucky to find a problem with the first cmdlet I tried! According to a Microsoft contact, the development team made a deliberate decision to correct what they see as bad patterns by making the All parameter a switch parameter instead of a boolean. This stance is perfectly justifiable, but it will cause some scripts to fail. In any case, the fix is easy: remove the $True.

$Users = Get-AzureADUser -All -Filter "Usertype eq 'Member'"

Behind the scenes, the Get-AzureADUser alias redirects the command to the Get-EntraUser cmdlet, which supports the same parameters:

$Users = Get-AzureADUser -All -Filter "Usertype eq 'Member'"

Given its intended purpose, it’s unsurprising that the cmdlets contained in the Entra module match those found in the AzureAD and AzureADPrevIew modules. To see the list of the available commands run the Get-Command cmdlet. The list reveals the available aliases too.

Get-Command -Module Microsoft.Graph.Entra

Now let’s find the manager of a user account. Usually, this command works without a problem:

$Manager = Get-AzureADUserManager -ObjectId $User.ObjectId

But in cases where the user account doesn’t have an assigned manager, the code barfs with:

Invoke-MgGraphRequest: GET https://graph.microsoft.com/v1.0/users/7bfd3f83-be63-4a5a-bbf8-c821e2836920/manager?$select=* HTTP/2.0 404 Not Found Cache-Control: no-cache Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000 request-id: 6622507b-c060-42f2-938e-a0225e756a70 client-request-id: 95d52d30-1faa-4891-82b2-783bfdf1e6bc x-ms-ags-diagnostic:
{"ServerInfo":{"DataCenter":"North Europe","Slice":"E","Ring":"4","ScaleUnit":"000","RoleInstance":"DU6PEPF00010AAA"}} x-ms-resource-unit: 1 Date: Fri, 28 Jun 2024 12:53:43 GMT
Content-Type: application/json Content-Encoding: gzip  {"error":{"code":"Request_ResourceNotFound","message":"Resource 'manager' does not exist or one of its queried reference-property objects are not
present.","innerError":{"date":"2024-06-28T12:53:43","request-id":"6622507b-c060-42f2-938e-a0225e756a70","client-request-id":"95d52d30-1faa-4891-82b2-783bfdf1e6bc"}}}

The aliasing translated the Get-AzureADUserManager cmdlet into a Graph API request against the Users API that failed because the select query in the request returned nothing.

I could go on and hammer home the point that translating all but the simplest use of AzureAD cmdlets into Graph API requests is difficult. You can expect problems to happen and be required to intervene to fix problems. Then I ask myself if problems are expected, why not simply embrace the full Microsoft Graph PowerShell SDK and update scripts to use it? As code is updated, it can be checked and improved, maybe even to improve performance by taking advantage of how the Graph retrieves data.

It’s not horribly difficult to migrate a script from the AzureAD module to the Microsoft Graph PowerShell SDK, especially if you invest in GitHub Copilot and use it with Visual Studio Code.

Same Permissions Used as for the Microsoft Graph PowerShell SDK

Because the Connect-Entra cmdlet is an alias for Connect-MgGraph, when you sign into an interactive session by running the Connect-Entra cmdlet, the session inherits the set of permissions held by the Microsoft Graph Command Line tools enterprise app, or rather the service principal for that app. These permissions accrue over time, so it’s important to keep an eye on what permissions are available during interactive sessions. Microsoft has published a best practices article for the Entra module that recommends using registered apps instead of the enterprise app to avoid permission overload. I think that’s good advice.

The fact that both cmdlets use the same app is easily confirmed by running Connect-Entra with a scope of a permission like POP.AccessAsUser.All that isn’t usually used by the Microsoft Graph PowerShell SDK. Up pops the consent dialog to reveal that the Microsoft Graph Command Line Tools app is the one seeking consent (Figure 1).

The Microsoft Graph Command Line Tools app requests consent for the Entra PowerShell module
Figure 1: The Microsoft Graph Command Line Tools app requests consent for the Entra PowerShell module

Astute observers will notice that the Microsoft Graph Command Line Tools app is now verified. This is a recent change announced in message center post MC804763 (24 June 2024). Previously, consent requests showed an unverified app, and who wants to give consent for permissions to an app that might come from an unverified source? Quite why it took so long for Microsoft to put the app through their own app compliance program is a mystery.

Weighing Up the Entra PowerShell Module

The downside of migrating scripts using the Microsoft Graph PowerShell SDK is that the SDK has its own set of foibles that can catch the unwary developer. Pipelining is a prime example because the Graph SDK cmdlets don’t support this fundamental PowerShell concept. But the Entra PowerShell cmdlets do, meaning that something like this is possible:

Get-AzureADUserManager -ObjectId cad05ccf-a359-4ac7-89e0-1e33bf37579e | Get-AzureADUser

Microsoft also points out that the new module comes with “human-readable parameters,” which is an interesting way of saying that Graph API requests and SDK cmdlets sometimes enjoy a syntax only penetrable after deep study.

When it becomes generally available, the Entra PowerShell module will serve a highly specific role to help organizations that still have not migrated PowerShell scripts using cmdlets from the old AzureAD and AzureADPreview modules to a modern base. Microsoft says that the module is part of their “ongoing commitment and increased investment” in the Microsoft Graph PowerShell SDK. If so, I wonder why they did all the work to create a new module instead of fixing the problems in the SDK? Having one solid and dependable module seems like a better strategy than splitting development effort across the two.

I won’t use the Entra PowerShell module because I’ve invested the best part of four years to become acquainted with the Graph APIs. Microsoft can be applauded for introducing a tool to help a subset of customers, but I have a nagging feeling that the Entra PowerShell module will be a source of confusion. My advice remains that customers should embrace the Graph and use the Microsoft Graph PowerShell SDK. But read the Entra module documentation and make your own mind up!

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Leave a Reply