Run Get-MgPolicyAuthenticationMethodPolicy against most tenants right now and it will tell you SMS is disabled, Microsoft Authenticator is disabled, and probably that voice calling is disabled too. Then look at the tenant and half the users are still getting texted a code every morning. Both of those things are true at once, and the reason why is the first trap in this article.
Microsoft announced on 13 July 2026 that passkeys become the default authentication method in Entra ID, and that SMS and voice MFA delivery stops entirely on 1 February 2027. No opt-out. Every tenant in the public cloud, new and existing.
| Date | What happens |
|---|---|
| 1 September 2026 | Passkeys become the default. Users enabled for SMS or voice are auto-enabled for passkeys and prompted to register one at their next MFA sign-in. |
| 18 September 2026 | Supported third-party telecom providers and pricing are published. |
| 30 October 2026 | Admins can select a third-party telecom provider through the Microsoft Security Store. |
| 1 February 2027 | Microsoft retires its own SMS and voice delivery. No opt-out. |
After 1 February 2027, anyone whose only registered second factor is a phone number cannot sign in. If your organisation still needs SMS after that date, you contract a telecom provider directly and pay for the traffic, and that provider relationship has to exist before the date, not after.
The obvious question is who in your tenant is actually exposed, and the console does not answer it in one place. So we wrote a script that does, and published it: Get-EntraSmsVoiceMfaExposure.ps1, in the PowerShell repo. It reads every enabled member account, lists their registered authentication methods, and sorts them into who's blocked, who's fine, and who's an administrator that shouldn't be either. It writes nothing to the tenant.
Before you run it, or anything else, against a real tenant, there are two things about how Entra ID reports its own state that will make the output look wrong even when it isn't.
Get-MgPolicyAuthenticationMethodPolicy returns a PolicyMigrationState alongside the per-method settings, and Microsoft documents three values: preMigration, migrationInProgress, migrationComplete. In the first two, the tenant is still honouring the legacy per-user MFA settings alongside the new methods policy, and the two are combined with OR logic. A method allowed in either place still works.
Every tenant we've audited so far reads migrationInProgress. Not migrationComplete. Not close to it. Just sitting there, mid-migration, indefinitely, because nothing forces it to finish.
That produces the symptom at the top of this article: the methods policy claims SMS and Authenticator are both off, and half the tenant is visibly using them, because the methods policy isn't the thing granting access. The legacy per-user settings are, quietly, in the background, unaffected by whatever the methods policy says.
Two things follow from that, and both matter before you touch a toggle:
Our script prints the migration state before it prints anything else, for exactly this reason: everything downstream of a preMigration or migrationInProgress reading should be read as "unknown," not "disabled."
The second trap sits on the other side of the 1 September date. Microsoft's announcement says users enabled for SMS or voice get auto-enabled for passkeys and prompted to register one at their next MFA sign-in. That only works if the tenant has FIDO2 turned on in the authentication methods policy. Most of the tenants we've checked don't.
Microsoft's announcement doesn't say what the prompt does when there's nothing to register against: whether it repeats, whether it blocks the sign-in, or whether it quietly gives up. We haven't seen that documented anywhere, so we're not going to guess at it here. The safer move is not finding out from a help desk queue on 2 September: check whether FIDO2 is enabled in the tenant's authentication methods policy before that date, not after.
The script needs a Global Reader (or Global Administrator) sign-in and four Microsoft Graph PowerShell modules, which it checks for and offers to install if they're missing. It's read-only: User.Read.All, UserAuthenticationMethod.Read.All, Policy.Read.All, RoleManagement.Read.Directory, Organization.Read.All.
.\Get-EntraSmsVoiceMfaExposure.ps1 -TenantId contoso.com
Say this runs against a fictional tenant, Contoso. The console output looks something like this:
Authentication methods policy: PolicyMigrationState = migrationInProgress
→ Legacy per-user MFA settings are still in effect. Treat "disabled" methods
in this policy as unknown, not off.
Scanning 214 enabled member accounts...
BLOCKED 1 Feb 2027 (SMS/voice is the only factor): 31 users
⚠ 2 of these hold a directory role — see below
Phone registered, has a surviving method: 58 users
No MFA method registered at all: 6 users
Clear: 119 users
Directory-role holders with SMS/voice as their only factor:
meredith.grant@contoso.com — User Administrator
dwight.schrute@contoso.com — Helpdesk Administrator
Unlicensed enabled accounts (excluding directory-role holders): 4
See ContosoMfaAudit-2026-08-13.csv for the full list.
Meredith and Dwight aren't real people at a real company; they're stand-ins so you can see the shape of the output without us pasting a client's tenant. The pattern is the one worth noticing: two of the thirty-one blocked users hold directory roles. The 1 February retirement doesn't stop at end users, it can take out the people who'd need to fix the problem.
The full CSV carries every account, its registered methods, and its verdict, so the follow-up (registering a passkey, enrolling Authenticator, whatever the remediation is) has a worklist instead of a guess.
Alongside the blocked list, the script reports enabled accounts with no licence assigned at all: usually a leaver who was never offboarded, or a shared mailbox whose user object was never blocked. Accounts holding a directory role are excluded from that list on purpose; an unlicensed admin account is more often a deliberate pattern than an oversight. The script can tell you nobody's paying for the account. It can't tell you nobody's using it.
Two more things worth knowing before you run it:
-IncludeSignInActivity adds a last-sign-in column, but it needs Entra ID P1 in the target tenant and a broader consent (AuditLog.Read.All). If the tenant is Office 365-only with no P1, that switch returns nothing useful. The signal doesn't exist to query.
Every Graph call in the script carries an explicit -ErrorAction Stop. The Graph SDK raises API failures as non-terminating errors, which $ErrorActionPreference = 'Stop' does not catch on its own. Without the explicit flag on every call, a 403 prints in red and the script carries on regardless, returning zero rows and a summary that looks like good news. It isn't. If you're adapting the script for something else, keep that pattern.
The list itself isn't the fix, it's the input to one. For every account on the BLOCKED list, register a second factor that survives 1 February 2027 (a passkey if FIDO2 is enabled, Microsoft Authenticator otherwise) before that date, not after. For the directory-role holders on that list, do it first; an administrator locked out is the account you need most on the day something else goes wrong.
If your tenant reads anything other than migrationComplete, get that sorted before you start switching methods off in the policy pane, or you'll disable something that's still quietly working through the legacy settings and call the job done when it isn't.
Passkeys and phishing-resistant MFA more broadly are the direction Microsoft is pushing every tenant regardless of this specific deadline. If you want help getting there rather than just auditing where you stand today, get in touch and we'll talk through what that looks like for your tenant.
The full script, with both parameters and the unattended-run switch, is in the Entra ID folder of the PowerShell repo.
1 February 2027, with no opt-out. After that, an organisation that still needs SMS has to contract a telecom provider directly.
Check PolicyMigrationState first. Anything other than migrationComplete means the legacy per-user MFA settings are still live alongside the methods policy, combined with OR logic.
Users get auto-enabled for passkeys and prompted to register one, but with FIDO2 off there's nothing for that registration to attach to. Check the tenant's FIDO2 setting before that date.
No. The retirement applies to every account equally; losing access to an admin account is just a worse day than losing access to a standard one.
