Use Multiple Data Sources to Calculate the MFA Status for User Accounts
Updated 12 June 2024
I’ve written about how to use the Microsoft Graph PowerShell SDK to manage Entra ID conditional access policies and how to report the settings for conditional policies. The natural next step is to figure out which user accounts are enabled for multifactor authentication (MFA). As has been noted many times, a high percentage of Microsoft 365 users don’t use MFA to protect their accounts, including accounts that hold administrative roles (like global administrator, Exchange administrator, or SharePoint administrator).
Increasing the percentage of MFA-enabled accounts remains a good goal for tenant administrators to pursue as we spin up work for 2024. To increase the percentage, we need to know what accounts use MFA today and those that do not. Let’s dive into the details of how we might get this information.
Finding MFA Information for User Accounts
A fundamental problem faced by anyone wishing to report the MFA status for a user account is that Microsoft will deprecate the MSOL module in March 2024 (full retirement will follow afterward). Following deprecation, the old method based on fetching the “strong authentication methods” using the Get-MsolUser cmdlet will be unsupported. In other words, this code might or might not continue to work:
$MsolUser = Get-MsolUser -UserPrincipalName $UserPrincipalName If ($MsolUser.StrongAuthenticationMethods) { Write-Host ("User {0} is enabled for MFA" -f $UserPrincipalName) }
Microsoft’s focus is firmly fixed on using conditional access policies to require inbound connections to use MFA. One of the reasons for not delivering a replacement method to report the MFA status for user accounts in the Graph APIs is that Microsoft is moving away from the per-user MFA capability available for Office 365 (E3 and above) accounts. Microsoft wants tenants to switch off per-user MFA and embrace conditional access policies instead.
To help, Microsoft plans to ship a managed conditional access policy to assist eligible tenants make the switch. The problem is that “eligible” means that tenants have the Entra ID P1 or P2 licenses necessary for conditional access policies. Customers who want to move away from per-user MFA to use conditional access as per Microsoft’s suggestions must pay extra to replace functionality that, although clunky and difficult to manage, still works.
Because the SDK cmdlets are derived from Graph APIs, the lack of Graph API support to enable or disable MFA for a user means that no SDK cmdlet is available to report the MFA status for an account. All we can do is interpret the authentication methods registered with Entra ID for their account and guess if the presence of a method like the Authenticator app implies that the account uses MFA. This information along with other settings is exposed in the User registration details report in the Entra ID admin center (Figure 1).
The Get-MgBetaReportAuthenticationMethodUserRegistrationDetail cmdlet makes the same information available. Both methods require the accounts that retrieve the registration information to have Entra ID P1 licenses. If you don’t currently have Entra ID P1 licenses, it’s a good idea to buy some and assign the licenses to administrators to enable access to this and other functionality.
The Get-MgUserAuthenticationMethod cmdlet can also retrieve information about the authentication methods registered for user accounts. If an account belongs to a restricted administrative unit, only administrators of the unit can retrieve information for the account. Attempts by other administrators, even those holding the global administrator role, result in a 403 forbidden error.
Validating MFA Connections
Knowing that an account is capable of using MFA is one thing; knowing that the account actively uses MFA is another. Entra ID preserves multifactor authentication usage data for 30 days. It’s possible to view the data about MFA usage in the Entra ID admin center by applying a filter (conditional access = success) to retrieve sign-in records for successful multifactor connections. The data includes connections from both member and guest accounts. You can browse the data online, but it’s easier to understand which accounts use MFA to connect by downloading the Interactive sign ins report in CSV format (Figure 2). The downloaded report contains records for the filtered sign-ins.
A file containing data for a month’s worth of connections to a tenant is a lot of information to deal with (Entra ID limits the file to a maximum of 100,000 records). Here’s what I do to reduce the data to a usable set:
- Move the downloaded CSV file to a suitable place for processing.
- Edit the CSV file to remove the “incoming token type” column. This column is duplicated and if left in place will stop the Import-CSV cmdlet working.
- Import the updated file to a PowerShell array using the Import-CSV cmdlet.
- Remove records for guest connections from the array and sort the remainder by user identifier to keep just unique values.
Here’s sample code:
[array]$MFASignIns = Import-CSV c:\temp\InteractiveSignIns.CSV [array]$MFAUserData = $MFASignIns | Where-Object {$_.'user type' -eq 'Member' -and $_.Status -eq 'Success'} | Sort-Object {$_.'Date (UTC)' -as [datetime]} | Sort-Object 'User ID' -Unique | Select-Object 'User ID', 'User', 'UserName', 'Date (UTC)','Multifactor authentication result', 'Multifactor authentication auth method'
The result is an array of member accounts that have successfully connected using MFA in the period covered by the downloaded file. Here’s an example of a record. The data tells us that James Ryan satisfied an MFA challenge sent by text message at 9:54am on December 28, 2023.
User ID : cad05ccf-a359-4ac7-89e0-1e33bf37579e User : James Ryan Username : James.Ryan@office365itpros.com Date (UTC) : 2023-12-28T09:54:26Z Multifactor authentication result : MFA completed in Azure AD Multifactor authentication auth method : Text message
By analyzing sign-in data, we can discover which accounts used MFA over the last 30 days. Given that some people might have been away for an extended period, it’s not a guarantee that this is the full set of accounts using MFA. Instead, it’s the set of accounts that are actively using MFA, which is useful knowledge to have.
Reporting MFA Status
Returning to the original question about knowing which accounts are enabled for MFA and which are not, let’s combine information from several sources to create an overview of user accounts, their password status, the last successful sign-ins for accounts, the time when user access sessions are valid from, and what we know about MFA enablement. The aim is to create an overview of how accounts connect to a tenant. The nice thing about PowerShell is that it is very good at pulling together data from various sources to create new insights.
In this instance, we do the following:
- Run Get-MgUser to find member accounts with a license. Member accounts without a license (like those used for room mailboxes) don’t use MFA.
- Get the MFA registration data by running the Get-MgBetaReportAuthenticationMethodUserRegistrationDetail cmdlet.
- Process each account to extract details like the timestamp for when the account password was last changed, the timestamp for the last successful sign-in and last sign-in (which could be a failed attempt), if any password policies apply to the account, the registered authentication types, if the account holds an administrator role, if the account is MFA capable, and so on.
Figure 3 shows an example of the report output, including some color coding to help administrators know when accounts have administrator roles or are MFA capable.
When writing the script, I integrated the user sign-in data downloaded from Entra ID to populate the “MFA last used” column. If the sign-in data is available, the script checks if a record is available to show if an account used MFA to connect. If a record is found, the script includes the timestamp for the connection, which is what you see in the highlighted entry in Figure 3, The MFA sign-in data confirms that an MFA-capable account actually uses MFA to connect and delivers a better assessment of the state of MFA usage within the tenant.
After generating details for all the user accounts, the script finishes up the report with some overall numbers for the tenant (Figure 4). The information is from my test tenant so it’s unsurprising that a relatively high percentage of accounts (41.18%) are not registered for MFA. On the upside, the 58.82% of accounts registered for MFA is substantially higher than the average for Microsoft 365 tenants. But the really interesting point is that only 45% of the accounts registered for MFA use multifactor connections. Something like a registration campaign might be useful to convince the recalcitrant users to fully embrace MFA.
The full script is available for download from GitHub. The normal caveats apply. The script works but it’s written to demonstrate a principle instead of being a complete solution. You might need to update the code to make the script work in your environment.
Update (June 2024): Microsoft has released a beta Graph API to retrieve the per-user MFA state for accounts. The latest version of the script reports if accounts are enabled, disabled, or enforced for per-user MFA.
Gaining Insight into MFA Status
Many web articles are available that tell you how to retrieve MFA status for user accounts. Those that use the old MSOL cmdlets will eventually stop working. Others who use the registration of specific authentication methods to indicate MFA enablement make assumptions that might not be true.
If you want to be sure about the MFA status for Entra ID user accounts, you’ve got to draw from multiple sources to have any chance of reaching a firm conclusion. Hopefully the method described here gives you an insight into how you might understand the MFA status of Entra ID accounts.
hi Tony
many thanks for taking the time to create all the reports you do.
in this report(from github) you have this section to get the date MFA is last used for a user.
$MFAVerifiedDate = $MFAUserData | Where-Object {$_.’User Id’ -eq $User.Id} | Select-Object -ExpandProperty ‘Date (UTC)’
If ($MFAVerifiedDate) {
$MFAVerifiedDate = (Get-Date $MFAVerifiedDate -format ‘dd-MMM-yyyy HH:mm’)
}
…
‘MFA last used’ = $MFAVerifiedDate
I dont see this property as being available in 2.16 of Get-MgBetaReportAuthenticationMethodUserRegistrationDetail
do you have this available to you?
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
The date comes from the information gathered from Entra ID logs. It is not returned by the cmdlet.
Great article. Any chance of a script or way to view what devices people are using to MFA? Ran into a scenario where a person had two phones registered and was only using one of them. I’m wanting to automatically go through our environment and see which devices have not been used in >30 days. Thanks!
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
I believe that some information can be extracted from the sign-in logs to help identify what devices are in use. Unhappily, Entra ID doesn’t capture device information for every sign-in record.
I see a lot of what we need via GUI; Identity – Protection – Authentication Methos – User registration Details
Multifactor Capable, Passwordless Capable, SSPR Capable, Default, Registered, Last Updates Time
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
The information you see in the Entra admin center tells you if someone has registred authentication methods that might be used with MFA. It does not tell you if they are using MFA.
As noted in the article, “The Get-MgBetaReportAuthenticationMethodUserRegistrationDetail cmdlet makes the same information available.”
It is by combining sign-in, registration, and user data that we can create a picture of whether accounts use MFA. That’s what the script does.
Hello Tony!
Thanks for sharing this information. As you say, I can’t use Get-MsolUser. I used a workaround using a GUI, entering Entra ID -> Users -> All Users and selecting Peer User MFA. The link opens the Multifactor authentication page.
This may help others.
Attention: This site does not permit export but allows seeing all MFA user statuses and changing them easily.
Best regards!
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
I think you mean “per-user MFA.”
The page gives access to per-user MFA enablement. However, it’s an old page that is due to go away when Microsoft deprecates per-user MFA (aka, legacy MFA) in favor of conditional access policies (to enforce MFA on a per-connection basis). I wouldn’t recommend anyone using per-user MFA now because you’ll only end up having to migrate.
Thank you. Found out I had quite a few different microsoft.graph versions installed. Had to remove all of them, then install latest+beta and that fixed the issue.
My last issue is that the date password last changed vs number of days since password changed seems to be a mismatch. I looked in your HTML output above and it seems to show the same issue. FYI
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Use this script to install the latest versions of Office 365 PowerShell modules including the SDK (and clean up old modules): https://office365itpros.com/2020/06/22/update-powershell-modules-m365/
I found a bug. Download the latest version of the script from GitHub and give it a whirl.
Thanks for the update! Seems to be working now. Thanks, again!
So far, it’s working great. Thanks for the effort and sharing. I’m only showing an issue where the default MFA field is blank for all user, so I’m troubleshooting that now.
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
What you should see…
[array]$MFAData = Get-MgBetaReportAuthenticationMethodUserRegistrationDetail
$User = get-MgUser -UserId “user@user.com”
$UserMFAStatus = $MFAData | Where-Object {$_.Id -eq $User.Id}
$UsermfaStatus | fl
DefaultMfaMethod : mobilePhone
Id : d36b323a-32c3-4ca5-a4a5-2f7b4fbef31c
There is a graphical report that can download MFA status as well here: https://portal.azure.com/#view/Microsoft_AAD_IAM/AuthenticationMethodsMenuBlade/~/UserRegistrationDetails
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Hi Joe,
The information displayed in the Entra admin center is the same as generated by the Get-MgBetaReportAuthenticationMethodUserRegistrationDetail cmdlet. The script uses that data as one of three sources of information:
Entra ID sign in timestamps for each account.
Entra ID audit records with sign-in details to confirm user activity.
MFA authentication methoods from Get-MgBetaReportAuthenticationMethodUserRegistrationDetail.
Together, information from the different sources give a picture of user MFA readiness and use.