Table of Contents
Work Ongoing on Other Projects – and Now the Microsoft Graph PowerShell SDK V2 Appears
Due to the deprecation of the Azure AD and Microsoft Online Services (MSOL) PowerShell modules (still scheduled for June 30, 2023), there’s been a lot of activity around upgrading scripts to use cmdlets from the Microsoft Graph PowerShell SDK. This is especially true for any script that performs license management activities as these cmdlets will stop working on March 31, 2023.
Microsoft’s documentation says, “Scripts written in Azure AD PowerShell won’t automatically work with Microsoft Graph PowerShell.” This is incorrect. The scripts won’t work at all because the cmdlets differ. Because the modules are based on very different technologies, no one-to-one translation from Azure AD cmdlets to SDK cmdlets either. Moving to a new module isn’t therefore not a matter of a quick edit to swap cmdlets over. Parameters and outputs differ. The effort needed to upgrade and test even a relatively simple script might extend to half a day or more.
The experience of using the SDK is growing within the technical community, but a knowledge gap still exists at times, especially when searching for good examples of how to accomplish a task. Microsoft’s documentation for the SDK cmdlets has improved recently, but it’s still not at the level that it should be.
Microsoft PowerShell Graph SDK V2
The current situation with the transition from Azure AD to SDK makes me think that Microsoft’s plan for changes in version two of the Microsoft PowerShell Graph SDK are badly flawed. The new version is still in the preview stage so things will probably change before general availability. At least, I hope that they do.
There’s some good changes lined up that I’ll cover first.
Although it’s possible to use V1 of the SDK with an Azure Automation managed identity, the method requires getting an access token from Azure and isn’t as clean as other implementations, such as those for Microsoft Teams and V3.0 of the Exchange Online management module. V2 of the SDK will allow you to connect using:
Connect-MgGraph -Identity
Support for managed identities will extend to user-created managed identities. Another change for authentication is support a credentials prompt when signing into the Graph. Finally, V2 supports certificate-based authentication.
Other changes include support for HTTP/2 and better handling by cmdlets for HTTP status codes.
Breaking Up is Hard to Do
V1 of the SDK is a giant module with 40 sub-modules (like Microsoft.Graph.Authentication). The size and unwieldly nature of the SDK means that it’s more difficult to manage than it should be. For instance, when Microsoft updates the SDK, the sub-modules used by developers on local PCs and in Azure Automation accounts require updating.
One reason why the SDK is so large is that it includes both V1.0 and beta version of cmdlets. This is because the Graph APIs that Microsoft generates the cmdlets from come in V1.0 and beta versions. Microsoft’s solution for the V2 SDK is to deliver separate modules: one for V1.0 (production) and another for beta.
Practical Side-Effects of Breaking the Microsoft Graph PowerShell SDK V2 into Two Modules
Conceptually, I don’t have any issue with the idea of splitting up the SDK into two modules. It’s on a practical level where my concerns kick in.
Today, a script can switch between V1.0 and beta by running the Select-MgProfile cmdlet. I do this all the time because the beta version of many cmdlets deliver more information than their V1.0 counterparts do. For example, Get-MgUser is a basic cmdlet to fetch details of an Azure AD user. The V1.0 cmdlet does not return license assignment data while the beta cmdlet does.
Select-MgProfile v1.0 Get-MgUser -UserId Tony.Redmond@office365itpros.com | fl assign* AssignedLicenses : AssignedPlans : Select-MgProfile beta Get-MgUser -UserId Tony.Redmond@office365itpros.com | fl assign* AssignedLicenses : {f61d4aba-134f-44e9-a2a0-f81a5adb26e4, 61902246-d7cb-453e-85cd-53ee28eec138, 26d45bd9-adf1-46cd-a9e1-51e9a5524128, 4016f256-b063-4864-816e-d818aad600c9...} AssignedPlans : {b44c6eaf-5c9f-478c-8f16-8cea26353bfb, fd2e7f90-1010-487e-a11b-d2b1ae9651fc,f00bd55e-1633-416e-97c0-03684e42bc42, 3069d530-e41b-421c-ad59-fb1001a23e11...}
Basic functionality issues afflict V1.0 cmdlets that operate against user accounts, groups, and other Azure AD objects. It would be nice if Microsoft fixed these problems and delivered a solid V1.0 module that allowed developers to focus on V1.0. Instead, the need exists to use the beta cmdlets.
Instead of making sure that many important cmdlets work like they should, Microsoft plans to drop the Select-MgProfile cmdlet. They say that “the profile design made the module bulky and error prone as it combined Microsoft Graph v1.0 and beta commands into a single module.” I accept that combining the two cmdlet sets in a single module is bulky, but is that a reason to remove a useful piece of functionality that allows developers to switch between V1.0 and beta cmdlets as needed? I don’t think it would take a lot of software engineering to figure out how to make the Select-MgProfile cmdlet load and unload modules as needed.
Even worse, Microsoft plans to introduce different names for the cmdlets in the two modules. Cmdlets in the V1.0 module will have the original names like Get-MgUser and Get-MgGroup. The beta cmdlets will have names like Get-MgBetaUser and Get-MgBetaGroup. Microsoft says that an advantage of their approach is that customers will be able to run V1.0 and beta cmdlets in the same script. In my experience, this never happens. Developers use Select-MgProfile to decide what cmdlets to use and then use cmdlets from that set. Mixing and matching cmdlets from different modules overcomplicates things.

The suggestion of using different names for cmdlets is just silly. It means that a developer must decide what module they want to use for a script up front to know what cmdlet names to use. Developers must check every existing script to identify if the correct cmdlet names are in place (and to deal with the Select-MgProfile issue). All the work done to upgrade scripts from the Azure AD and MSOL modules will need revalidation. That’s work Microsoft is forcing on tenants at a time when the Exchange development group wants tenants to upgrade their Exchange scripts to remove dependencies on Remote PowerShell. Forcing tenants to upgrade scripts for Exchange and Azure AD at the same time is an example of a lack of joined-up thinking within Microsoft.
I hear that Microsoft might generate a tool to help developers move to V2 by updating references to the beta cmdlets to use the new names. That might help, but work still needs to be done to review scripts before and after the tool runs and test to make sure that the updated script works. And what happens if Microsoft updates the V1.0 cmdlets and a decision is made to revert to that version? You’ll still have to update scripts manually.
A Way Forward for the Microsoft Graph PowerShell SDK V2
What I would like to see done in the Microsoft Graph PowerShell SDK V2 is:
- Repurpose the Select-MgProfile cmdlet so that it switches between the two modules as transparently as possible.
- Keep the same cmdlet names in both modules. It then becomes a choice for the developer as to which cmdlets to use.
- Fix the V1.0 of basic user and group cmdlets like Get-MgUser and Get-MgGroup so that they return the information necessary to get real work done. If the V1.0 cmdlets delivered that functionality, the need to switch to beta wouldn’t be as pressing. The problems must be fixed in the Graph API rather than the SDK (which simply replicates what the Graph API does).
The precedent for having cmdlets with the same name in production and development modules exists. We’ve used the AzureAD and AzureADPreview modules in this manner for years. Why Microsoft can’t do the same with V2 of the Microsoft Graph PowerShell SDK is beyond me.
In any case, the first preview version of the Microsoft Graph PowerShell SDK V2 is available to download from the PowerShell Gallery. Test it and see what you think. The important thing is to give feedback to Microsoft (you can comment in GitHub). If you don’t, then the current plan is what will flow through to the Generally Available release of the Microsoft Graph PowerShell SDK V2 sometime in 2023.
So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.
What they should do is produce cmdlets designed with usability in mind, instead of relying on auto-generated crap. But their priority seems to be “make our devs life easier”, instead of making their customer’s life easier…
Then again, they’ll likely start charging for PowerShell access if they decide to put actual effort into this module 😛
I am not a fan. When one line of code like this:
Set-MsolUserLicense -UserPrincipalName $newmbx.UserPrincipalName -AddLicenses nswrfs:SPE_E3,nswrfs:MCOMEETADV,nswrfs:POWER_BI_STANDARD,nswrfs:ATP_ENTERPRISE
gets replaced with this
$E3Sku = Get-MgSubscribedSku -All | Where SkuPartNumber -eq ‘EXCHANGESTANDARD’
$E3Sku1 = Get-MgSubscribedSku -All | Where SkuPartNumber -eq ‘EXCHANGEARCHIVE_ADDON’
$E3Sku2 = Get-MgSubscribedSku -All | Where SkuPartNumber -eq ‘EXCHANGEARCHIVE_ADDON’
$addlicensesE3 = @(
@{SkuId = $E3Sku.SkuId},
@{SkuId = $E3Sku1.SkuId}
@{SkuId = $E3Sku2SkuId}
)
Set-MgUserLicense -UserID $newmbx.UserPrincipalName -AddLicenses $addlicensesE3 -RemoveLicenses @()
That is a backward step. and who in their right mind would replace UPN with UserID. just stupid.
Although I have some sympathy for the argument you advance, once you get used to the way that the Graph works, things become easier. See https://practical365.com/microsoft-365-license-graph-sdk/ and https://practical365.com/create-licensing-report-microsoft365-tenant/ for more about license management with the SDK