My AzureAD scripts still run today. Do I actually need to migrate?
Yes. Not “eventually” — now, on your schedule, before someone else’s schedule picks the date for you.
Microsoft has deprecated the AzureAD, AzureADPreview and MSOnline modules and is steering everyone to the Microsoft Graph PowerShell SDK — that’s Microsoft’s own published position, not mine. When retirement lands, the cmdlets don’t get a polite deprecation warning — the underlying endpoints stop answering. Your nightly license-assignment job doesn’t fail loudly at 9 a.m. where you’d see it. It fails at 2 a.m., silently, and you find out when the helpdesk queue fills up with people who can’t reach a mailbox. Migrate while it’s a project, not an incident.
Confirm the current retirement status yourself before you plan around a date — Microsoft has moved these timelines more than once, and I’m not going to quote you a day that shifts. The live source of truth is the deprecation notice on the Microsoft Entra blog and the “Migrate from Azure AD PowerShell to Microsoft Graph PowerShell” guidance on Microsoft Learn. Check those, not a blog’s memory of a date.
Is Microsoft.Graph just the old module with a new name?
No, and pretending otherwise is how migrations go sideways. The Microsoft Graph PowerShell SDK is a different shape: different cmdlet nouns (Mg prefix), different parameter names, different auth model, different default behaviours. Get-AzureADUser becomes Get-MgUser — that mapping is published in the Microsoft Learn migration guide — but that’s where the comfort ends.
The big conceptual shift: the SDK talks to Microsoft Graph, so you now think in terms of Graph permissions (scopes) and Graph property names. A script that “just worked” because your admin session implicitly had rights now has to ask for those rights explicitly. That’s more friction, and it’s also the point — you can finally see exactly what a script is allowed to do.
Do I use Microsoft.Graph or the new Microsoft Entra PowerShell module?
It depends, but here’s the short version: if you’re writing new automation, start with Microsoft.Graph. If you’re migrating old AzureAD scripts and want the least rewriting, look at the Microsoft Entra PowerShell module (Microsoft.Entra), which — per its Microsoft Learn documentation — is built on the same Graph foundation but keeps cmdlet shapes closer to the ones your fingers already know.
They’re not rivals — Entra PowerShell sits on top of the Graph SDK. Pick one per script and stay consistent. Mixing connection contexts in a single runbook is a debugging tax you’ll pay later. My default: Graph SDK for anything I’m building fresh, Entra module when I’m porting a pile of legacy AzureAD calls and want to minimise the diff.
Why does Connect-MgGraph throw a permissions error when the same admin worked fine before?
Because the SDK doesn’t inherit your directory role rights automatically — you request scopes, and the tenant (or an admin) consents to them. If you didn’t ask for a scope, you don’t have it, regardless of how much of a Global Admin you are. This is how Connect-MgGraph is documented to work on Microsoft Learn.
Ask for read scopes when you’re only reading. The moment a script needs User.ReadWrite.All or Directory.ReadWrite.All, that’s a flag in code review, not a default you reach for. If consent fails, an admin has to approve the scope in the tenant first — that’s working as intended, even when it’s inconvenient at 2 a.m.
Get-MgUser only returns 100 users. Where did the rest go?
Nowhere — you’re seeing one page. The SDK paginates, and the default page is small (the Microsoft Graph paging documentation covers this). This is the single most common “my report is wrong” bug in freshly migrated scripts, because it fails quietly: no error, just an undercount that looks plausible.
Use -All for anything that needs a complete set. Ask for the -Property fields you actually use — pulling every attribute for 40,000 users is slow and rude to the service. And wrap it in -ErrorAction Stop inside a try/catch so a throttling blip doesn’t leave you with a half-empty array you then treat as gospel.
Why do advanced filters throw a “not supported” error?
Because some Graph queries need the advanced query engine, and you have to opt in with -ConsistencyLevel eventual and -CountVariable. Filtering on things like endsWith, or counting, or ordering on certain properties won’t work without it — Microsoft documents this under “Advanced query capabilities on directory objects.”
If a filter mysteriously returns nothing or errors, add the consistency header before you assume the data’s missing. Nine times out of ten that’s it.
How do I bulk-update users without nuking my tenant?
Never pipe a live query straight into a write cmdlet. That’s the “I’ll just disable the stale accounts real quick” command that becomes a Sev 1. Split it into two phases: export and review, then act on the reviewed file, with -WhatIf on by default.
Note -UserId, not -ObjectId — that rename is in the Update-MgUser reference, and it’s exactly what breaks a naive find-and-replace migration. The signInActivity property is another trap: per the Microsoft Graph user resource docs it needs the AuditLog.Read.All scope and a Microsoft Entra ID P1 or P2 license to be populated, so a null last-sign-in means “unknown,” not “never.” Don’t disable on nulls.
What replaces Get-MsolUser and Set-MsolUserLicense for licensing?
Get-MgUser for the read, Set-MgUserLicense for the write. The license object model is different — as the Set-MgUserLicense reference shows, you pass SKU IDs in a structured body rather than the old string-friendly parameters.
Group-based licensing in Entra ID is the better answer for anything recurring — let group membership drive assignment and stop hand-running license scripts entirely. Verify assignments in the Entra admin center under Billing > Licenses and on the user’s Licenses blade.
Can I run this unattended in Azure Automation?
Yes — and this is where you stop using interactive login. Use a managed identity or an app registration with a certificate, granted the exact application permissions the runbook needs. No secrets in the script, no passwords in variables. The -Identity switch on Connect-MgGraph is documented for exactly this.
Grant that identity read-only scopes wherever the job only reports. Reserve write scopes for the runbooks that genuinely change state, and document which is which. When an audit asks “what can this automation do,” you want the answer to be one line in a consent screen, not a shrug.
Will migrating break my break-glass access?
It shouldn’t — break-glass accounts are cloud-only admins you sign in with interactively, not automation. But test them before you retire the old modules, not after, and confirm they’re excluded from the Conditional Access policies you’re about to lean on. The one time you need that account is the one time you can’t afford a surprise.
What’s the one thing that bites people six months later?
Scope creep in reverse: someone requests Directory.ReadWrite.All “to be safe” during migration, admin-consents it, and it never gets walked back. A year on it’s a standing write permission nobody remembers granting, sitting on an app registration nobody owns. Migrate to least privilege now, review consented scopes quarterly, and treat every ReadWrite as a decision you have to defend. The Graph SDK finally makes those permissions visible — the mistake is not looking.
Where do I verify all this before trusting a blog?
Good instinct. Don’t take my word for any of it — take Microsoft’s. Everything above traces back to primary docs:
- Deprecation status and timeline — the Microsoft Entra blog deprecation announcements for the AzureAD, AzureADPreview and MSOnline modules, and “Migrate from Azure AD PowerShell to Microsoft Graph PowerShell” on Microsoft Learn. This is the only place I’d trust for a current retirement date.
- Cmdlet and parameter mapping (
Get-AzureADUser→Get-MgUser,-ObjectId→-UserId) — the same migration guide, plus the individualGet-MgUserandUpdate-MgUsercmdlet references. - Scopes and consent (
User.Read.All,Directory.Read.All,AuditLog.Read.All) and theConnect-MgGraph -Identityflow — the Microsoft Graph PowerShell authentication docs on Microsoft Learn. - Pagination and
-All— the Microsoft Graph paging documentation. - Advanced queries (
-ConsistencyLevel eventual,-CountVariable) — “Advanced query capabilities on directory objects” in the Microsoft Graph docs. signInActivitylicensing and permission — the Microsoft Graphuserresource reference, which states the P1/P2 license andAuditLog.Read.Allrequirement.- Licensing cmdlets — the
Set-MgUserLicenseandGet-MgSubscribedSkureferences, and the group-based licensing docs in the Microsoft Entra ID documentation.
If any of those pages disagrees with me, believe the page. That’s the whole discipline: trust the source that gets updated, not the one that got written once.
