DEV Community

Cover image for Migrating from Deprecated AzureAD & MSOnline to Microsoft Graph PowerShell SDK
Alessandro Mainardi
Alessandro Mainardi

Posted on Originally published at alexmaina.dev

Migrating from Deprecated AzureAD & MSOnline to Microsoft Graph PowerShell SDK

📖 Original Reference: Originally published with full script translation matrices and Graph SDK pipelines at alexmaina.dev/ms365.

Microsoft has officially retired the legacy AzureAD and MSOnline (MSOL) PowerShell modules. Any legacy scripts still executing Get-AzureADUser, Set-MsolUserLicense, or Connect-MsolService face broken endpoints, authentication failures, and deprecation notices.

The replacement is the Microsoft Graph PowerShell SDK (Microsoft.Graph). However, migrating isn't just a simple 1:1 cmdlet rename: the Graph SDK has fundamentally different scoping, JSON-based payload structures, and paging mechanisms.

Here is the practical, crash-course guide to modernizing your scripts for Microsoft Graph PowerShell v2, including unattended certificate authentication for CI/CD runners.


1. Quick Cmdlet Translation Matrix

Old AzureAD / MSOnline Modern Microsoft Graph SDK Key Difference
Get-AzureADUser -ObjectId $id Get-MgUser -UserId $id Properties are lazy-loaded; use -Property
Get-AzureADGroup Get-MgGroup -All Must explicitly specify -All to paginate
Add-AzureADGroupMember New-MgGroupMemberByRef Requires @{"@odata.id" = "..."} format
Set-MsolUserLicense Set-MgUserLicense Uses modern GUID SKU IDs
Get-AzureADDevice Get-MgDevice -All Device attributes match Entra ID schema

2. The Pagination Trap: Why Get-MgUser Returns Only 100 Items

One of the most frequent surprises for administrators migrating from Get-AzureADUser is that Get-MgUser defaults to returning only the first 100 records.

If you have 1,500 users, running Get-MgUser without flags leaves 1,400 users unprocessed:

# ❌ INCORRECT: Truncates at 100 users
$users = Get-MgUser

# ✅ CORRECT: Automatically follows nextLink pagination tokens
$allUsers = Get-MgUser -All

# 🚀 PERFORMANCE TIP: Only request the properties you actually need
$optimizedUsers = Get-MgUser -All -Property "id", "displayName", "userPrincipalName", "mail"
Enter fullscreen mode Exit fullscreen mode

3. Adding Group Members the Modern Way (New-MgGroupMemberByRef)

In legacy modules, you passed simple IDs. In the Microsoft Graph SDK, relations are established via OData references:

# Legacy AzureAD (BROKEN):
# Add-AzureADGroupMember -ObjectId $groupId -RefObjectId $userId

# Modern Microsoft Graph:
$params = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$userId"
}
New-MgGroupMemberByRef -GroupId $groupId -BodyParameter $params
Enter fullscreen mode Exit fullscreen mode

4. Unattended CI/CD Automation (No Passwords or MFA Prompts)

Automated backup scripts and DevOps deployment pipelines cannot use interactive Connect-MgGraph browser logins. You must authenticate using an App Registration with an X.509 Certificate.

Step 1: Connect via Certificate Thumbprint

On your management server or GitHub Actions runner:

$tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$appId    = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
$thumbprint = "1234567890ABCDEF1234567890ABCDEF12345678"

# Authenticate unattended
Connect-MgGraph -TenantId $tenantId -ClientId $appId -CertificateThumbprint $thumbprint -NoWelcome
Enter fullscreen mode Exit fullscreen mode

Step 2: Running Least-Privilege Queries

Always scope your App Registration to the minimum required permissions (e.g. User.Read.All instead of Directory.ReadWrite.All):

# Export all active users to CSV safely
Get-MgUser -All -Filter "accountEnabled eq true" -Property "displayName", "mail", "department" | 
    Select-Object DisplayName, Mail, Department | 
    Export-Csv -Path "ActiveEmployees.csv" -NoTypeInformation

# Disconnect session cleanly
Disconnect-MgGraph
Enter fullscreen mode Exit fullscreen mode

5. Installing Only What You Need (Save Disk Space & Startup Time)

The monolithic Microsoft.Graph module downloads dozens of sub-modules and consumes over 1GB of disk space. For lightweight scripts or container runners, install only the specific sub-modules:

# Instead of installing all 38 Graph modules:
# Install-Module Microsoft.Graph

# Install ONLY the modules required by your script:
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.Users -Scope CurrentUser
Install-Module Microsoft.Graph.Groups -Scope CurrentUser
Enter fullscreen mode Exit fullscreen mode

Execution times drop from 15 seconds to under 2 seconds.


Conclusion

Migrating to the Microsoft Graph PowerShell SDK future-proofs your enterprise automation, aligns your scripts with standard REST APIs, and allows rock-solid unattended execution with certificate-based authentication.

Author: Alessandro Mainardi — Software Developer & Microsoft 365 Cloud Architect. Explore enterprise automation playbooks at alexmaina.dev/ms365.

Top comments (0)