Skip to the main content.

ScriptRunner Blog

Are you ready for Destination Graph? – Azure AD and MSOnline module are deprecated by March 2024

Table of contents



Post Featured Image

With MS Online and Azure AD module deprecation, it's time to map previous tasks to new methods. We hope the following ideas will help you.

Are you affected?

Microsoft is deprecating some important PowerShell Modules come the end of March 2024 with the MS Online (MSOL) and Azure AD/Preview modules targeted for this date. While Microsoft announced these changes years ago, it appears the ride for these modules is now coming to an official end.

What does this mean for you, if you use these modules for IT administration and for migration projects? 

It means it's time to learn how to use Graph PowerShell and find a way to map previous tasks to the new methods. Some administrators have adapted to this change and have no issues, while others will find that the Microsoft Graph PowerShell module is a less forgiving module and a barrier to getting tasks done. In this article, we will tackle these challenges, review examples of how these changes will affect PowerShell users as well as review Microsoft's help documentation for this transition.


What’s deprecating?

  • Azure AD / Azure AD Preview
  • Microsoft Online (MSOL or MSOnline)


Deprecation notifications

Microsoft, as is typical of large changes, has taken time to gradually nudge administrators to make changes and prepare for the future. Notifications are almost two years in-progress: 

June 2022 / June 2023 / September 2023 / December 2023

There are probably more notifications out there, but this is a small sample to review. 


Migrating to Graph

Microsoft has provided resources to assist those with migrating cmdlets, scripts and apps:

  • Migrate Azure AD Graph (link)
  • Migrating apps (link)
  • Migration steps (link)


Compatibility checker

Use this tool to check your script for compatibility and is available in the PowerShell Gallery.


Graph PowerShell basics

If you are new to using Graph, the process for connecting and preparing is similar to other PowerShell modules.

First, install the Microsoft Graph SDK PowerShell module:

Install-Module Microsoft.Graph

Then import the module into PowerShell:

Import-Module Microsoft.Graph

Connecting to Graph: This is a very quick example because there are some nuances to Graph as it’s more granular in terms of tasks / permissions. See this article for more details on connecting to Graph, choosing permissions and more. 

Connect-MgGraph -Scopes 'Directory.ReadWrite.All'


Real world examples

In this section, we will review some brief examples of some tasks that were performed in the legacy modules and how to now perform them in Graph PowerShell. 



(1) List all users in a tenant

MSOnline Service Module:


Microsoft Graph PS Module:
(Get-MgUser -ALL).Count

01_graph and MSonline image

Top is Graph with 119 users and the bottom example is from MS Online with 119 users as well.


(2) List guest or tenant member users with a one-liner

MSOnline Service Module:
Get-MsolUser | Where-Object UserType -eq Member | Sort-Object DisplayName


MSOnline Output:

02_MSOnline output

Now, to do the same in the Graph module, we perform a filtered lookup:

Get-MgUser -All -Filter "UserType eq 'Member'"


Graph Output:
03_Graph output

Default output is different and thus needs adjusting to depending on what properties of the user is needed.


(3) Group licensing

Licensing is also vastly changed and the previous steps now need to be performed in Microsoft Graph. Previously, I had written an article for this blog on this topic, you can find "Licensing with Microsoft Graph PowerShell" here.


(4) User authentication methods

Authenticating an account in a Microsoft 365 tenant may require some additional authentication methods (a.k.a. MFA) which can further validate who is connecting to the account. In the MSOnline service, there is a way to set the Strong Authentication settings, but with the deprecation of the module Graph is now our tool. Graph PowerShell has a bit of granularity which we will explore here. First, MSOnline:

$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = "*"
$st.State = "Enabled"
$sta = @($st)
Set-MsolUser -UserPrincipalName -StrongAuthenticationRequirements $sta

Graph has numerous cmdlets, but keep in mind that the above is now considered legacy not only in terms of method (per user MFA) but also the module (MSOnline). We can made adjustments to it via Graph PowerShell. First, query the configuration for a user:

-UserId | Format-List

04_user authentication method

We see that this user does have MFA configured, using three different methods for verification. Graph PowerShell allows us to remove an existing method with Remove-MgUserAuthentication* cmdlets, add new authentication methods with New-MgUserAuthentication* cmdlets, update the authentication methods with Update-MgUserAuthentication* cmdlets or list individual settings with Get-MgUserAuthentication* cmdlets. While per user MFA configuration is not generally recommended, we may need to make adjustments if a user has a user, or if an authentication method simply is not working.


Add method – Phone authentication:

In this example, we are adding the phone authentication method for a user and defining it as their mobile number:

$params = @{
    phoneNumber = "+1 3125551212"
    phoneType = "mobile"
New-MgUserAuthenticationPhoneMethod -UserId -BodyParameter $params


Update method:

In this example, we need to use the same $params variable to define the new phone number, we also need the existing phone authentication method as we could have multiple lines defined and finally the update cmdlet:

$PhoneAuthID = (Get-MgUserAuthenticationPhoneMethod -UserId postmaster@
$params = @{
    phoneNumber = "+1 3125551212"
    phoneType = "mobile"
Update-MgUserAuthenticationPhoneMethod -UserId postmaster@ -BodyParameter $params -PhoneAuthenticationMethodId $PhoneAuthId


Remove method:

If we need to update an existing phone authentication method (cannot have two of the same type) or if we just wish to remove the authentication method, we can do so with PowerShell:

$PhoneAuthID = (Get-MgUserAuthenticationPhoneMethod -UserId
Remove-MgUserAuthenticationPhoneMethod -UserId -PhoneAuthenticationMethodId $PhoneAuthID


Azure AD examples

(1) Adding users to a group

In this example, commonly used to add new users to a licensing group or a permissions group, PowerShell needs to read a CSV file for a list of users to process and then populate the group:


Azure AD code:

$CSV = Import-Csv .\MailboxesToAdd.txt
Foreach ($User in $CSV) {
  $ID = $User.Alias
  $UPN = $ID+''
  $ObjectID = (Get-AzureADUser -ObjectId $UPN).ObjectID
  Add-AzureADGroupMember -ObjectId a616b6a9-21ad-41f3-8204-f52e944d9df4 -RefObjectId $ObjectID


Graph example:

$CSV = Import-Csv .\MailboxesToAdd.txt
Foreach ($User in $CSV) {
  $ID = $User.Alias
  $UPN = $ID+''
  $ObjectID = (Get-MgUser -UserId $UPN).Id
  New-MgGroupMember -GroupId a616b6a9-21ad-41f3-8204-f52e944d9df4 -DirectoryObjectId $ObjectID

With this example, we see that two cmdlets change, from the Azure AD cmdlets to Graph specific cmdlets. Fairly easy to do. Note that parameters will change as well in most cases.


(2) Query all user details

In this example, we are querying a list of properties of a user that could be used for documentation, verification or possibly to archive if a user object is moved between tenants.

Get-AzureADUser -Top 500 | Where-Object UserType -eq member | Sort-Object DisplayName | Select-Object UserPrincipalName, DisplayName, GivenName, Surname, Mail, MailNickName, Company, Country, Department, Title, Mobile, PostalCode, State, StreetAddress, TelephoneNumber, UsageLocation | Export-Csv -Path "c:\downloads\atlantix\$Tenant-AzureAD-Export.csv" -NoTypeInformation



With two different modules being deprecating at once, and both having some overlap already, it is worth noting that some cmdlets in Azure AD and the MSOnline PowerShell module may end up mapping to a single cmdlet in the Graph PowerShell module. Some examples below:


Get-MgUser (Graph)

Get-CorrespondingGraphCommand Get-AzureADUser
Get-CorrespondingGraphCommand Get-MsolUser

What we see is that, in Graph, both of these cmdlets from different modules use the Get-MgUser as its successor. 


Note that despite the overlap, it is not ideal as not all parameters and options are the same, so true conversion will take time and learning.


Get-MgGroupMember (Graph)

Another example of this are groups that exist in your tenant. In the past we’ve had a series of cmdlets that manage these groups, from both MSOnline and AzureAD. Below we see that the Get cmdlets end up pointing to the same Graph PowerShell cmdlet:

Get-CorrespondingGraphCommand Get-MsolGroupMember
Get-CorrespondingGraphCommand Get-AzureADGroupMember

We see the resulting cmdlet is Get-MgGroupMember:



The future

Good tools going forward

When finding a corresponding cmdlet in Graph, we have a couple of methods of discovery:


Single cmdlets

Combine the tool with the ability to check what Graph permissions are needed to run the Graph cmdlet. Take for example the Get-MsolUser cmdlet, a typical cmdlet from the MSOnline PowerShell Module. Using the DependencySearch PowerShell module, we can pull the matching cmdlet and use a Graph cmdlet to pull the permissions:

$NewCmdlet = (Get-CorrespondingGraphCommand Get-MSOLUser).GraphCommand
(Find-MgGraphCommand $NewCmdlet).Permissions

Below is a subset of the output from these two one liners:

07_output from our one liners

Sample of the full list of permissions for the Get-MsolUser cmdlet

The one complication is that some cmdlets have a large corresponding list of permissions that grant access to the cmdlet. Choose least permission, starting with the Read versions of permissions if you can.


Whole scripts

It’s one thing to translate a single cmdlet, but it is entirely different when we have entire scripts that we may need to perform the same translation. With the same DependencySearch module, we can analyze our scripts for potential issues. In the below example, we first pull all available modules and then apply the search function against a sample script "C:\Repository\ScriptToAnalyze.ps1".

$AvailableModule = @(Get-Module -ListAvailable)
Get-CodeDependency -scriptPath "C:\Repository\ScriptToAnalyze.ps1" -AvailableModules $AvailableModule

Results of these two lines will then output cmdlets that need to be replaced with Graph cmdlets:




Conclusion – Final word

Microsoft has moved the final dates for this change many times and we cannot expect this to change again. Now is the time to make your changes, learn how to use Graph and move on from these legacy PowerShell modules. Otherwise, you may be caught with a critical script that is no longer functional or worse a business process that no longer processes and costs your organization monetary losses.



ScriptRunner fully supports Microsoft Graph since 2022

Our ScriptRunner MS Graph Targets allows you to simplify and centralize the use of MS Graph for managing your Microsoft 365 subscriptions. 

good-to-know-graph 1

Our ScriptRunner MS Graph Queries enable you to easily receive data via the Microsoft Graph API. 

good-to-know-graph 2

Read more in our ScriptRunner online documentation. We also wrote a blogpost when we first introduced Microsoft Graph as a new service for M365 targets


Click here for our documentation




Related links 

Related posts

4 min read

How do I create PFX files with PowerShell?

7 min read

Teams Webhooks via PowerShell – Modern Alerting (part 1/3)

12 min read

Licensing with Microsoft Graph PowerShell

About the author: