📖 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"
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
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
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
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
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)