Microsoft Graph PowerShell SDK V2.0 Reaches General Availability

Release of Microsoft Graph PowerShell SDK V2.0 an Example of Poor Communications

Updated: 14 August 2023

On July 4, 2023 when the Microsoft world was very quiet due to the U.S. holiday, the Graph SDK development team made V2.0 of the Microsoft Graph PowerShell SDK generally available through the PowerShell Gallery. Despite the ramifications of moving to V2.0 of the SDK, I can find no public announcement of this fact in a Microsoft Technical Community blog or Microsoft 365 message center notification (both mandatory for announcements of this nature that affect Microsoft 365 tenants). Vasil told me of a Devblogs post dated July 7, but that’s not a place where tenant admins pick up their news.

I only started to look for evidence of general availability after I noticed that some documentation featured 2.0 examples and the Graph X-Ray tool began to output V2.0 code.

Microsoft Graph PowerShell SDK V2.0 (but only the V1.0 endpoint cmdlets)
Figure 2: Microsoft Graph PowerShell SDK V2.0 (but only the V1.0 endpoint cmdlets)

Update: Since the original release of the SDK, Microsoft has pushed out several updates to fix issues that have become apparent since the transition to the new module. The current version is V2.3.

Microsoft announced the preview of the Microsoft Graph PowerShell SDK V2 in December, 2022. At the time, I expressed some doubts, not least the proposal to split the Microsoft Graph PowerShell SDK V2.0 into V1.0 (production) and beta modules. The intention to speed up load time and reduce the overall size of the module was good. My doubt centered on the potential impact on customer scripts, especially as organizations had to figure out how to move from the AzureAD and MSOL modules. Microsoft’s decision to push out the final deprecation of those modules until March 30, 2024 eased the pressure to update, but the fact remains that customers migrated and wrote scripts from scratch using SDK V1.0. The changes Microsoft proposed implied further work to check, modify, and test any script created using SDK V1.0.

The moment of truth arrived. Microsoft documentation now centers on SDK 2.0 and the development group met their target to shop SDK 2.0. However, no guidance exists about how to check scripts written using SDK 1.0 for SDK 2.0. The foibles we learned to live with in SDK 1.0 have not gone away and some new issues have appeared. Did anyone say that life was good?

Updating to Microsoft Graph PowerShell SDK 2.0

Upgrading to SDK 2.0 is easy. I recommend that you reboot your PC to make sure that PowerShell has no loaded module and then create a new Administrator session. Run the Update-Module cmdlet to fetch the Microsoft.Graph module from the PowerShell gallery and you’ll soon have SDK 2.0. Alternatively, use the script to upgrade all Office 365 modules (including the SDK) including the essential step of removing old versions (I’ve updated the script for SDK 2.0).

The problem is that updating the Microsoft.Graph module only updates the V1.0 module. If you want to use the beta cmdlets to interact with the beta Graph endpoint, you must install the beta module separately:

Install-Module Microsoft.Graph.Beta -AllowClobber

Upgrading to Microsoft Graph PowerShell SDK V2.0 Cmdlets

Microsoft has a migration tool in the shape of a PowerShell module. The tool is a cmdlet to scan a script and update cmdlet names with beta cmdlet names where appropriate. Having a tool is nice, but it’s not enough to verify that every cmdlet will work as before after upgrading to SDK V2.

Chapter 23 of the Office 365 for IT Pros eBook (2024 edition) covers PowerShell and the Graph. It includes hundreds of code examples, including many based on SDK 1.0. I spent the weekend going through every example to see what works and what doesn’t. We’ll release the results of that work (and reviews of SDK examples in other chapters) in our August 2023 update. In the interim, here are some first impressions:

When you run Connect-MgGraph to connect to the Graph, you use the V1.0 cmdlets. When checking scripts, the first thing to look for is the presence of the Select-MgProfile cmdlet, used by the V1.0 SDK to switch between V1.0 and beta endpoints. As the V1.0 endpoint is the default, the usual command is:

Select-MgProfile beta

Once you see this command in a script, you know that you’ll need to remove the command and update the SDK cmdlets to use beta cmdlets. For example:

Get-MgUser becomes Get-MgBetaUser.

Get-MgGroup becomes Get-MgBetaGroup.

Get-MgSubscribedSku becomes Get-MgBetaSubscribedSku, and so on.

Rushing to use the beta cmdlets is a simplistic upgrade strategy. Before deciding to use a beta cmdlet, check the V1.0 cmdlet to see if it does what you need. If it does, use the V1.0 cmdlet. For example, in SDK V1.0, I always used the beta cmdlets whenever fetching details of user licenses. For example, this code finds user accounts with at least one assigned license:

[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All

The command works, but the V1.0 cmdlet doesn’t retrieve the assignedLicenses property that holds the license information. The beta cmdlet does retrieve the license data, which is why it seems like a good thing to use. However, you can instruct Get-MgUser to retrieve assignedLicenses by including the Property parameter, meaning that scripts can use the V1.0 cmdlet:

[array]$Users = Get-MgUser -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable Records -All -Property id, displayName, userPrincipalName, assignedLicenses

On the other hand, if a V1.0 cmdlet doesn’t work, it’s worth trying its beta counterpart to see if it succeeds. As an example, the Update-MgUser cmdlet can’t update values for Azure AD custom security attributes but the Update-MgBetaUser cmdlet can.

Problems Noted with Microsoft Graph PowerShell SDK V2.0 Cmdlets

Apart from the expected work to replace beta cmdlets with new cmdlet names, I found a couple of other issues. The strong caveat is that I only reviewed cmdlets used in examples. There might be other problems lurking in SDK 2.0. Here are my notes:

The cmdlets that update properties like group owners and user managers operate by reference, passing an identifier to point to the account of the new owner or manager. With SDK V1.0, I could pass the identifier of a new group owner like this:

New-MgGroupOwnerByRef -GroupId $GroupId -AdditionalProperties @{"@odata.id"="https://graph.microsoft.com/v1.0/users/2a3b60f2-b36b-4758-8533-77180031f3d4"}

Running the code in V2.0 signals an error:

cmdlet New-MgGroupOwnerByRef at command pipeline position 1
Supply values for the following parameters:
OdataId:

However, passing the identifier for the new owner through the BodyParameter parameter works:

$UserId = (Get-MgUser -UserId Rene.Artois@office365itpros.com).id
$OwnerId = ("https://graph.microsoft.com/v1.0/users/{0}" -f $UserId)
$NewOwner = @{"@odata.id"=$OwnerId}
New-MgGroupOwnerByRef -GroupId $GroupId -BodyParameter $NewOwner

SDK V2.0 cmdlets are more precise about specifying what properties cmdlets should retrieve. For instance, using the V1.0 code, I could do this to find the last sign-in activity for guest accounts using the beta endpoint:

[array]$Guests = Get-MgUser -Search $Search -ConsistencyLevel Eventual -Property SignInActivity -All
If (!($Guests)) { Write-Host "No matching account can be found"; break }
ForEach ($G in $Guests) {
   If ($G.UserType -eq "Guest") {
      If (!([string]::IsNullOrWhiteSpace($G.SignInActivity.LastSignInDateTime))) {
          $Days = New-TimeSpan($G.SignInActivity.LastSignInDateTime)    
          Write-Host ("Guest member {0} last signed in on {1} or {2} days ago" -f $G.DisplayName, $G.SignInActivity.LastSignInDateTime, $Days.Days ) }
      Else { Write-Host ("No recent sign-in data available for {0} ({1})" -f $G.DisplayName, $G.Mail)  }
     }
}

With SDK 2.0, if you use the V1.0 endpoint, make sure that you request the properties you want to use in your script. Returning a minimal set of object properties is a quirk of the SDK cmdlets. It’s done for performance reasons but it’s different to the way other workload modules work.

[array]$Guests = Get-MgUser -Search $Search -ConsistencyLevel Eventual -Property SignInActivity, id, DisplayName, userPrincipalName, userType -All

My initial attempts to fetch the Microsoft 365 Groups policy template resulted in an error because a failure to load version 1.28 of the Microsoft.Graph.Authentication sub-module:

$GroupTemplate = (Get-MgDirectorySettingTemplate | Where-Object {$_.DisplayName -eq "Group.Unified.Guest"})
WARNING: Unable to find type [Microsoft.Graph.PowerShell.Authentication.Utilities.DependencyAssemblyResolver].
Get-MgDirectorySettingTemplate : Could not load file or assembly 'Microsoft.Graph.Authentication, Version=1.28.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file
specified.

When I checked the loaded modules, I found two references to V1.28.0. I have no idea why these versions of the modules still existed on the PC (the script to update modules should have removed the older files). I assume that the files were loaded when the script attempted to remove them.

Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.0      Microsoft.Graph.Applications        {Add-MgApplicationKey, Add-MgApplicationPassword, Add-MgSe...
Script     2.0.0      Microsoft.Graph.Authentication      {Add-MgEnvironment, Connect-MgGraph, Disconnect-MgGraph, G...
Script     1.28.0     Microsoft.Graph.Authentication      {Add-MgEnvironment, Connect-MgGraph, Disconnect-MgGraph, G...
Script     2.0.0      Microsoft.Graph.Beta.Identity.Di... {Complete-MgBetaDirectoryImpactedResource, Complete-MgBeta...
Script     2.0.0      Microsoft.Graph.Beta.Reports        {Confirm-MgBetaAuditLogSignInCompromised, Confirm-MgBetaAu...
Script     2.0.0      Microsoft.Graph.Groups              {Add-MgGroupDriveListContentTypeCopy, Add-MgGroupDriveList...
Script     1.28.0     Microsoft.Graph.Identity.Directo... {Complete-MgDirectoryImpactedResource, Complete-MgDirector...

After exiting all PowerShell sessions, I deleted the on-disk directories for V1.28.0 of Microsoft.Graph.Authentication and Microsoft.Graph.Identity.DirectoryManagement (for instance, C:\Program Files\WindowsPowerShell\Modules\Microsoft.Graph.Authentication\1.28.0). After deleting the files, I updated the script to use the Get-MgBetaDirectorySettingTemplate to make everything work. This experience points to the need to clear out old V1.0 modules from PCs to make sure that they are not loaded.

Installing the Microsoft Graph PowerShell SDK 2.0 on a new PC won’t run into this problem.

Time Needed to Move to Microsoft Graph PowerShell SDK V2.0

While I don’t like Microsoft’s communications around making SDK V2.0 generally available, moving to the new version isn’t horrible. It’s just another thing that must be done, another time drain on PowerShell developers. Now I have to go and review my SDK-based scripts to upgrade them to V2.0. Joy!


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

6 Replies to “Microsoft Graph PowerShell SDK V2.0 Reaches General Availability”

    1. Hi Carol, I note the announcement in the article. My complaint is that this is such a big update that it should have been flagged to Microsoft 365 tenant administrators through a message center notification. What’s the point in having a mechanism to advise tenants of changes that impact their environments if Microsoft development groups don’t use those routes?

  1. I finally got around to reviewing/testing all of my scripts against V2.x. Your post was very helpful. Thank you.

    One thing that did trip me up briefly was the rename of the “DeviceManagement.Enrolment” module to “DeviceManagement.Enrollment” as mentioned here:

    https://github.com/microsoftgraph/msgraph-sdk-powershell/blob/dev/docs/upgrade-to-v2.md#renamed-devicemanagementenrolment-module-to-devicemanagementenrollment

    My own module management process left the old 1.28.0 module when I updated to 2.4.0. One of the cmdlets I was using in a script (Get-MgRoleManagementDirectoryRoleDefinition) was found in the 1.28.0 DeviceManagement.Enrolment module (but was apparently moved to the Identity.Governance module in 2.x). This caused a similar “failure to load version 1.28” error. Uninstalling the old/misspelled/1.28 version solved the problem for me:

    Uninstall-Module -Name Microsoft.Graph.DeviceManagement.Enrolment -Force

    I’ll also note that after installing 2.x of the SDK and uninstalling any matching 1.28.0 modules, my system still has three 1.28.0 modules that don’t appear to be included in the 2.x version – but do appear in the Beta module:

    1.28.0 Microsoft.Graph.Financials
    2.4.0 Microsoft.Graph.Beta.Financials

    1.28.0 Microsoft.Graph.ManagedTenants
    2.4.0 Microsoft.Graph.Beta.ManagedTenants

    1.28.0 Microsoft.Graph.WindowsUpdates
    2.4.0 Microsoft.Graph.Beta.WindowsUpdates

    I’ll likely remove the 1.28 version of these modules and wait for them to be promoted to the non-beta 2.x package.

    1. I suspect that the 1.28 modules which didn’t progress to V2 only ever held cmdlets that are now in the beta module, which is why you see them in the V2 V1.0 module. As to Enrolment versus enrollment, that might be the correction of a module that originally used UK-style English because some of the SDK development is done in Kenya.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.