One of the reports that I really miss in the Microsoft 365 Admin Center is a clear overview of the MFA status of each user. MFA is a really important security measure to protect your tenant. To make sure that our users have configured MFA we are going to use PowerShell to get and export the MFA Status.
You could also use the built-in overview in the Admin Center, but that would be really time-consuming. With PowerShell on the other hand, we can easily get the MFA Status of all users and create an Excel list with all the details we need.
I have created a script that can do a couple of things to check and report the MFA status of your users:
- List the MFA Status of all users
- List configured MFA types for each user
- Get all the users that don’t have MFA enabled
- Check the MFA status of a single user
- Check if MFA is enforced
- Checks if a user is admin or not
- Get only the licensed and enabled users
At the end of the article, you will find the complete script.
Note
I have also created this script based on Microsoft Graph. It will get a bit more information then this script. Make sure you check it out!
Get the MFA Status with PowerShell
With PowerShell, we can easily get the MFA Status of all our Office 365 users. The basis for the script is the Get-MsolUser cmdlet, which gets the users from the Azure Active Directory.
Get-MsolUser returns all the user details, including the parameter StrongAuthenticationMethods. This parameter will list all the strong authentication methods that a user is using. If this parameter is set, then we know that the user is using MFA.
Tip
Add this script to your PowerShell Profile so you can easily check the MFA Status of your users. Read more about it in this article.
Requirements
You need to have the MsolService module installed to use this script. Make sure you are connected before you run the script.
Connect-MsolService
Getting a list of all users and their MFA Status
You can just run the script without any parameters to get a list of all the users and their MFA Status. The script will check if the user is an admin and will list the default MFA type that the user has set.
You can export the result on the screen or to a CSV file if you like.
# Make sure you are connected to MsolService Get-MFAStatus.ps1 | FT # Or if you want an excel file Get-MFAStatus.ps1 | Export-CSV c:\temp\mfastatus.csv -noTypeInformation
Get only the users without MFA
If you have a large tenant then you probably only want to get the users without MFA. You can use the switch withOutMFAOnly
for this.
Get-MFAStatus.ps1 -withOutMFAOnly
Check the MFA Status of admins
Admins should have MFA enabled without a doubt. To quickly check the status of all your admin accounts you can use the switch adminsOnly
Get-MFAStatus.ps1 -adminsOnly
Check the MFA status on a selection of users
The script also allows you to check the MFA Status of a single user or multiple users.
Get-MFAStatus.ps1 -UserPrincipalName '[email protected]'
If you want to check the status of a single department for example, then you can do the following:
Get-MsolUser.ps1 -Department 'Finance' | ForEach-Object { Get-MFAStatus $_.UserPrincipalName }
The complete script
You can find the complete script here below or you can get it here from my Github. (I recommend using Github to make sure you have the latest version).
Tip
Quickly get the MFA Status of your users by adding a reference to the script in your PowerShell Profile. Read all about it in this article.
<# .Synopsis Get the MFA status for all users or a single user. .DESCRIPTION This script will get the Azure MFA Status for your users. You can query all the users, admins only or a single user. It will return the MFA Status, MFA type ( .NOTES Name: Get-MFAStatus Author: R. Mens - LazyAdmin.nl Version: 1.3 DateCreated: jan 2021 Purpose/Change: List all Configured MFA Types Thanks to: Anthony Bartolo .LINK https://lazyadmin.nl .EXAMPLE Get-MFAStatus Get the MFA Status of all enabled and licensed users and check if there are an admin or not .EXAMPLE Get-MFAStatus -UserPrincipalName '[email protected]','[email protected]' Get the MFA Status for the users John Doe and Jane Doe .EXAMPLE Get-MFAStatus -withOutMFAOnly Get only the licensed and enabled users that don't have MFA enabled .EXAMPLE Get-MFAStatus -adminsOnly Get the MFA Status of the admins only .EXAMPLE Get-MsolUser -Country "NL" | ForEach-Object { Get-MFAStatus -UserPrincipalName $_.UserPrincipalName } Get the MFA status for all users in the Country The Netherlands. You can use a similar approach to run this for a department only. .EXAMPLE Get-MFAStatus -withOutMFAOnly | Export-CSV c:\temp\userwithoutmfa.csv -noTypeInformation Get all users without MFA and export them to a CSV file #> [CmdletBinding(DefaultParameterSetName="Default")] param( [Parameter( Mandatory = $false, ParameterSetName = "UserPrincipalName", HelpMessage = "Enter a single UserPrincipalName or a comma separted list of UserPrincipalNames", Position = 0 )] [string[]]$UserPrincipalName, [Parameter( Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "AdminsOnly" )] # Get only the users that are an admin [switch]$adminsOnly = $false, [Parameter( Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "AllUsers" )] # Set the Max results to return [int]$MaxResults = 10000, [Parameter( Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Licenend" )] # Check only the MFA status of users that have license [switch]$IsLicensed = $true, [Parameter( Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "withOutMFAOnly" )] # Get only the users that don't have MFA enabled [switch]$withOutMFAOnly = $false, [Parameter( Mandatory = $false, ValueFromPipeline = $false )] # Check if a user is an admin. Set to $false to skip the check [switch]$listAdmins = $true ) # Connect to Msol if ((Get-Module -ListAvailable -Name MSOnline) -eq $null) { Write-Host "MSOnline Module is required, do you want to install it?" -ForegroundColor Yellow $install = Read-Host Do you want to install module? [Y] Yes [N] No if($install -match "[yY]") { Write-Host "Installing MSOnline module" -ForegroundColor Cyan Install-Module MSOnline -Repository PSGallery -AllowClobber -Force } else { Write-Error "Please install MSOnline module." } } if ((Get-Module -ListAvailable -Name MSOnline) -ne $null) { if(-not (Get-MsolDomain -ErrorAction SilentlyContinue)) { Connect-MsolService } } else{ Write-Error "Please install Msol module." } # Get all licensed admins $admins = $null if (($listAdmins) -or ($adminsOnly)) { $admins = Get-MsolRole | %{$role = $_.name; Get-MsolRoleMember -RoleObjectId $_.objectid} | Where-Object {$_.isLicensed -eq $true} | select @{Name="Role"; Expression = {$role}}, DisplayName, EmailAddress, ObjectId | Sort-Object -Property EmailAddress -Unique } # Check if a UserPrincipalName is given # Get the MFA status for the given user(s) if they exist if ($PSBoundParameters.ContainsKey('UserPrincipalName')) { foreach ($user in $UserPrincipalName) { try { $MsolUser = Get-MsolUser -UserPrincipalName $user -ErrorAction Stop $Method = "" $MFAMethod = $MsolUser.StrongAuthenticationMethods | Where-Object {$_.IsDefault -eq $true} | Select-Object -ExpandProperty MethodType If (($MsolUser.StrongAuthenticationRequirements) -or ($MsolUser.StrongAuthenticationMethods)) { Switch ($MFAMethod) { "OneWaySMS" { $Method = "SMS token" } "TwoWayVoiceMobile" { $Method = "Phone call verification" } "PhoneAppOTP" { $Method = "Hardware token or authenticator app" } "PhoneAppNotification" { $Method = "Authenticator app" } } } [PSCustomObject]@{ DisplayName = $MsolUser.DisplayName UserPrincipalName = $MsolUser.UserPrincipalName isAdmin = if ($listAdmins -and $admins.EmailAddress -match $MsolUser.UserPrincipalName) {$true} else {"-"} MFAEnabled = if ($MsolUser.StrongAuthenticationMethods) {$true} else {$false} MFAType = $Method MFAEnforced = if ($MsolUser.StrongAuthenticationRequirements) {$true} else {"-"} } } catch { [PSCustomObject]@{ DisplayName = " - Not found" UserPrincipalName = $User isAdmin = $null MFAEnabled = $null } } } } # Get only the admins and check their MFA Status elseif ($adminsOnly) { foreach ($admin in $admins) { $MsolUser = Get-MsolUser -ObjectId $admin.ObjectId | Sort-Object UserPrincipalName -ErrorAction Stop $MFAMethod = $MsolUser.StrongAuthenticationMethods | Where-Object {$_.IsDefault -eq $true} | Select-Object -ExpandProperty MethodType $Method = "" If (($MsolUser.StrongAuthenticationRequirements) -or ($MsolUser.StrongAuthenticationMethods)) { Switch ($MFAMethod) { "OneWaySMS" { $Method = "SMS token" } "TwoWayVoiceMobile" { $Method = "Phone call verification" } "PhoneAppOTP" { $Method = "Hardware token or authenticator app" } "PhoneAppNotification" { $Method = "Authenticator app" } } } [PSCustomObject]@{ DisplayName = $MsolUser.DisplayName UserPrincipalName = $MsolUser.UserPrincipalName isAdmin = $true "MFA Enabled" = if ($MsolUser.StrongAuthenticationMethods) {$true} else {$false} "MFA Default Type"= $Method "SMS token" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "OneWaySMS") {$true} else {"-"} "Phone call verification" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "TwoWayVoiceMobile") {$true} else {"-"} "Hardware token or authenticator app" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "PhoneAppOTP") {$true} else {"-"} "Authenticator app" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "PhoneAppNotification") {$true} else {"-"} MFAEnforced = if ($MsolUser.StrongAuthenticationRequirements) {$true} else {"-"} } } } # Get the MFA status from all the users else { $MsolUsers = Get-MsolUser -EnabledFilter EnabledOnly -MaxResults $MaxResults | Where-Object {$_.IsLicensed -eq $isLicensed} | Sort-Object UserPrincipalName foreach ($MsolUser in $MsolUsers) { $MFAMethod = $MsolUser.StrongAuthenticationMethods | Where-Object {$_.IsDefault -eq $true} | Select-Object -ExpandProperty MethodType $Method = "" If (($MsolUser.StrongAuthenticationRequirements) -or ($MsolUser.StrongAuthenticationMethods)) { Switch ($MFAMethod) { "OneWaySMS" { $Method = "SMS token" } "TwoWayVoiceMobile" { $Method = "Phone call verification" } "PhoneAppOTP" { $Method = "Hardware token or authenticator app" } "PhoneAppNotification" { $Method = "Authenticator app" } } } if ($withOutMFAOnly) { # List only the user that don't have MFA enabled if (-not($MsolUser.StrongAuthenticationMethods)) { [PSCustomObject]@{ DisplayName = $MsolUser.DisplayName UserPrincipalName = $MsolUser.UserPrincipalName isAdmin = if ($listAdmins -and ($admins.EmailAddress -match $MsolUser.UserPrincipalName)) {$true} else {"-"} MFAEnabled = $false MFAType = "-" MFAEnforced = if ($MsolUser.StrongAuthenticationRequirements) {$true} else {"-"} } } }else{ [PSCustomObject]@{ DisplayName = $MsolUser.DisplayName UserPrincipalName = $MsolUser.UserPrincipalName isAdmin = if ($listAdmins -and ($admins.EmailAddress -match $MsolUser.UserPrincipalName)) {$true} else {"-"} "MFA Enabled" = if ($MsolUser.StrongAuthenticationMethods) {$true} else {$false} "MFA Default Type"= $Method "SMS token" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "OneWaySMS") {$true} else {"-"} "Phone call verification" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "TwoWayVoiceMobile") {$true} else {"-"} "Hardware token or authenticator app" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "PhoneAppOTP") {$true} else {"-"} "Authenticator app" = if ($MsolUser.StrongAuthenticationMethods.MethodType -contains "PhoneAppNotification") {$true} else {"-"} MFAEnforced = if ($MsolUser.StrongAuthenticationRequirements) {$true} else {"-"} } } } }
Wrapping up
Enabling MFA is one of the important steps to protect your tenant. With this PowerShell script, you can easily check the MFA status of your users.
Make sure you also check this article with 20 other security tips for Office 365.
If you found this script useful, then please share it. If you have any questions then just drop a comment below.
You may also like one of the following PowerShell report scripts:
Hi Rudy,
I know this article is old, but I was just trying to get MFA status of a department:
Get-MsolUser.ps1 -Department ‘Finance’ | ForEach-Object { Get-MFAStatus $_.UserPrincipalName }
I seem to be missing Get-MsolUser.ps1, and can’t find it on you GitHub – can you point me in the right direction.
Awesome site btw.
Thanks, and here is the script on GitHub: https://github.com/ruudmens/LazyAdmin/blob/master/Office365/MFAStatus.ps1
Hey Rudy
Thanks for the reply!
After a lot of trial and error I managed to get it working – but for the life of me have no idea how sorry!
Hi
When i run the script to output to csv it just gives me a list of numbers.
Help!
Joe
And what are the results when you just run
Would you know how I could run this script unattended, not interactively, so that I could run it weekly from a scheduled task that could email the results to myself?
The best way to do this is to use Azure Runbooks. Read more about it in this article: Use Azure Automation and PowerShell to Automate Office 365 Tasks
And: How to use Azure Managed Identity
I have a persistent error with Select-MgProfile Beta
Constantly tells me its not recognised.
I’ve deleted and reinstalled the graph module several times and closed down powershell but keeps cropping up.
Hi Rudy,
I think it’s a very nice powershell script and use it quite regularly, only what I don’t quite understand is why I don’t always get an MFA type back. When I run the script I see MFA enabled and enforced for some users, but no MFA type.
The script was missing the StrongAuthenticationMethods TwoWayVoiceOffice. I have added it to the script. Please get the latest version from GitHub and try again.
Very nice, thanks! It does indeed work with the latest version.
Is there also a possibility to retrieve the registered TwoWayVoiceOffice telephone number, just like with the OneWaySMS and the TwoWayVoiceMobile
I have updated the script with the alternative phonenumber, please check if that is the correct one. I don’t anyone with an office phone number registered in my tenants.
I get the same output as the version before. I would also not know where I can find this telephone number within the 365 admin portals
Can you check the results of the following command:
I get only AlternativePhoneNumber and PhoneNumber as relevante property.
Sorry for the delay, I don’t get any data in the output when I run the command. Only just the descriptions
ExtensionData : System.Runtime.Serialization.ExtensionDataObject
AlternativePhoneNumber :
Email :
OldPin :
PhoneNumber :
Pin :
Sorry I can’t find anything else about it. Only that TwoWayVoiceOffice should be the alternative phonenumber next to the mobile number that is register. So the number should either be return in the register phone or alternative phone attribute.
OK thanks! Anyway, thanks a lot for how the script works!
Hello Rudy, one noteworthy observation I made while running this script is that it consistently prompts me to select a userid and password for each account. Is there anything specific that I should add to the script to avoid this?
What kind of account are your using to run the script. Seems like an permissions issue.
The global administrator account is utilized for retrieving the information.
That is strange. What happens when you try to retrieve a single user with
Get-MsolUser -UserPrincipalName
after you have connected to msol ofcourse?Great script. As already mentioned, unlicensed admins are not recognized. Normally a user has a licensed user account and an unlicensed admin account which is ok.
I have updated the MgGraph MFA Status script. If you want to use this script and get all admins, inc without license. Then all you need to do is change
-property EmailAddress
to-property displayname
at the end of line 137I noticed a weird issue: If I run the script as such get-mfastatus.ps1 | ft, the results I get show all users except at least one that I noticed.
If I run get-mfastatus.ps1 -UserPrincipalName ‘[email protected]’ (the user that I noticed missing) I can see his information.
So it works, but not completely. 🙂 Not sure what I am missing. 🙁
I am looking for an overview of users and the activated apps (in their licenses).
Is this possible?
What kind of apps do you exactly mean? Which Microsoft 365 apps like onenote, teams etc they are using?
Is there a way to also show the users manager listed in AD to this script?
Technically, yes. With PowerShell, we can pull all kinds of data together. But the challenge is that you can’t retrieve the manager with the MSOL module. You will need to use MgGraph or the AzureAD module for that. So that will require some rewriting of the script.
Check out these articles to get started: Get-AzureADUser and Get-MgGraphUser
Hi Rudy,
First, I would like to thank you for all your great articles. This scrip is exactly what I needed, however I get an error and I am, not sure why, and how to fix it.
When I run the command Get-MFAStatus.ps1 | FT I see an error as follow:
Get-MFAStatus.ps1 : The term ‘Get-MFAStatus.ps1’ is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:1 char:1
+ Get-MFAStatus.ps1 | FT
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-MFAStatus.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
However, if I run the same as .\Get-MFAStatus.ps1 | FT then the script works and I can see the data in a file table format on the screen. I will appreciate if you or someone else can let me know why I have the error above and what shall I do to fix it?
Regards
You get the error because PowerShell doesn’t know where to find Get-MFAStatus.ps1 by default. So you will need to use the relative path .\Get-MFAStatus.ps1. To solve this you could change your PowerShell Profile
Great script, thanks Rudy.
I do have a question, how can we add the users department to the exported CSV?
That kind of user information isn’t part of the msol cmdlet. You will need to use the AzureAD module for this. So to incorporate this in the existing script, you will need to connect to AzureAD.
Then, for example, in the foreach loop at line 219, also get the user details for each user.
Excellent script, thank you.
Amazing Ruud, tbis is one of the best script out there for MFA.
You are amazing in Scripts.
good luck champ.
Is it also possible to display the MFA method ‘WindowsHelloForBusiness’ using the script?
I have created a new MFA script based on Microsoft Graph that will also list Hello for Business
Just a typo : Getting a list of all users and their (not there) MFA Status
😉
Thanks
Great script, it works well. Since MSOnline will be deprecated later this year, how can I achieve the same results with MgGraph? Using MgGraph I can get the methods with Get-MgUserAuthenticationMethod but can’t seem to find the bit to simply tell me if MFA is enabled/disabled/enforced, etc. Any guidance here would be appreciated.
It is now marked as “After dec 2022”, so no need to worry about it right now.
I already have explored MgGraph, but am still unable to achieve the same results at the moment. I will keep an eye on it and create a script for it when possible. Just follow the newsletter 😉
Is there a way to do this in Powershell v7 on Linux or Mac?
Thanks for the script!
However, it doesn’t seem te really reflect actual use of MFA. It only shows if user have registered MFA, but users aren’t actually challenged to use MFA.
Looking in the Microsoft365 admin center (GUI), I can see that users still have MFA “Disabled”. We need to set the status to enforced from the GUI to ensure users are challenged for MFA.
So beware that this script only reports MFA registration and not actual MFA being used or enforced.
Hey James,
The script should get the StrongAuthenticationRequirements from the Msoluser. If that is set to true, then MFA is enforced, which means the user needs to configure MFA the next time he or she logs in. If “MFA Enabled” is empty, then no method is configured.
This script is really good!
Is there an option to either:
Only display MFA status for users in a specfic OU or to output all the results to include the OU container of the users to the Excel file so I can then use the filtering in Excel to only display users in a specified OU ?
My Powershell skills are not that good. Any help appreciated.
Thanks.
Can anyone help with this or is it not possible ?
A simple option would be to do:
$users = Get-ADUser -Filter * -SearchBase "OU=IT,OU=Amsterdam,OU=Sites,DC=Lazyadmin,DC=NL"
$users.ForEach{
Get-MFAStatus -UserPrincipalName $_.UserPrincipalName
}
But that won’t export the results into a single CSV.
Another option would to change line 218 to something like this:
$MsolUsers = Get-ADUser -Filter * -SearchBase "OU=IT,OU=Amsterdam,OU=Sites,DC=Lazyadmin,DC=NL" | Get-MsolUser -UserPrincipalName $_.UserPrincipalName | Where-Object {$_.IsLicensed -eq $isLicensed} | Sort-Object UserPrincipalName
Great work!
We have a very large user population over 20k and the script is not reporting on every user. I ran the script with $IsLicensed = $True and $IsLicensed = $false and it still only picks up a subset of users, around 5000k. Any thoughts on why its not reporting all users?
thanks again for all your hard work on this.
Gaz
Just to be sure, have you set the max results parameter to 20000?
And the code below, does it get all users? (change the export path)
Get-MsolUser -EnabledFilter EnabledOnly -All | Where-Object {$_.IsLicensed -eq $true} | Sort-Object UserPrincipalName | Export-CSV c:\temp\allusers.csv
having trouble loading a list of UPNs to check and use in a foreach one liner, any tips?
You can combine an import-csv with a foreach loop;
Import-Csv -Path c:\temp\test.csv | ForEach-Object { Get-MFAStatus $_.UserPrincipalName }
I notice you did not include the email method in the list of methods you export. I really needed that. I have some older users in our Non-Profit who don’t even have a mobile phone.
I have updated the script on Github, it will now also list the registered mail address and phone number. However, I don’t see an option to check if the email is set as default. As far as I know, this isn’t also possible in Office 365.
If it’s in your tenant, could then share the results of the following PowerShell code:
$msoluser = Get-MsolUser -UserPrincipalName [email protected]
$MsolUser.StrongAuthenticationMethods
Is there a way to run this only for users who have OWA enabled?
You will have to change line 211 to first get all OWA enabled mailboxes:
Get-CASMailbox -ResultSize unlimited | where {$_.OWAEnabled -eq "$true"} |
And then look up the user from those mailboxes. You can then get the MSOL details for each of that user.
Hi Rudy, great script that we used
Is it possible to also get/include the devices that a user has registered for the authenticator app? I suspect many users have old registrations that needs to be cleaned up.
Not with the MSOL module. It’s however possible with the MgGraph module using the Get-MgUserAuthenticationMethod cmdlet. I have a script laying around for that, but need to work it out further
Is it possible to add Dept and CompanyName to the output – I think that Dept should be OK as it is part of the MSOnlineUser cmdlet but what about Company?
What company information / field are you looking for? We have the company name listed in the “office” field. You could use Get-MsolCompanyInformation, but that only gives the tenant company information.
Thank you for that! Brilliant script
I think I am doing something wrong. When I run the Get-MFAStatus.ps1; I get an error message that is it not recognized. What am I doing wrong?
You did save the script, and have opened PowerShell in the same location? Check otherwise this article : https://lazyadmin.nl/powershell/run-a-powershell-script/
Loving the script, been looking for something like this for a while.
Did try to modify it to work for partners, repeatedly trying to create lists for dozens of managed companies should be a crime.
Tried creating a loop around your code to query Get-MsolPartnerContract or even Get-PartnerCustomer from the PartnerCenter module but I either get blank outputs or no output at all. Both allow for Get-MsolUser but when I try to combine everything, no luck.
I can do Get-MsolPartnerContract | Get-MsolUser -EnabledFilter EnabledOnly to get all users from all tenants but not Get-MsolPartnerContract | Get-MsolUser -EnabledFilter EnabledOnly | Where-Object {$_.IsLicensed -eq $isLicensed} – or the rest of your script from line 211.
Am I missing something simple?
I just tried it and seems to work fine on my end with multiple tenants
$MsolUsers = Get-MsolPartnerContract | Get-MsolUser -EnabledFilter EnabledOnly | Where-Object {$_.IsLicensed -eq $true} | Sort-Object UserPrincipalName
Thanks! Shouldn’t have been trying late at night. Got it to work now by only changing this one line.
Now to figure out why all the admin accounts are showing up as not being an admin. 🙂
The script matches the email address with the userprincipal name. That may not match in your situation.
if ($listAdmins -and $admins.EmailAddress -match $MsolUser.UserPrincipalName) {$true} else {"-"}
Think it has to do with the if (($listAdmins) -or ($adminsOnly)) { } function.
That won’t query the other tenants, just my own. And I don’t see a quick fix to combine it with Get-MsolPartnerContract
Will do without. This has more than helped me along.
That is possible, but you will have to rebuild the script a bit. To get the admins from the other tenants, you could add something like this:
get-msolrole -TenantId $tenant.TenantId | %{$role = $_.name; Get-MsolRoleMember -RoleObjectId $_.objectid -TenantId $tenant.TenantId} | Where-Object {$_.isLicensed -eq $true} | select @{Name="Role"; Expression = {$role}}, DisplayName, EmailAddress, ObjectId | Sort-Object -Property EmailAddress -Unique
Hey, Sorry to Necro this specific reply! Thank you for great article and script!
Not sure if you are still replying/monitoring this article…?
I’m trying to do the same as @Wouter – run this script via the MS Partner Center.
I have adjusted the line as per above but get an error calling Get-MsolUser.
“Get-MsolUser : Access Denied. You do not have permissions to call this cmdlet”
“FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.AccessDeniedException,Microsoft.Online.Administration.Automation.GetUser”
Thanks for this article Ruud!
I will use your script to gather some details. Your article was the first I found in a search.
Greetings from the USA. On my next visit to NL I will need to offer to buy you a beer!
I ran the script in powershell ISE by hitting run and it disabled all users that had already MFA enabled? can you help figure out what line cause all MFA enabled users to go Enabled = False?
I double-checked the script (in the article and on GitHub) and there is no set command in it, only get.
So it’s impossible that this script is changing the MFA settings of your users. Are you sure that the settings are disabled, and not that the reporting is maybe wrong?
Guest users are missing.
Have you set -Licenend:$false ? Otherwise, it will only get licensed users.
-IsLicensed:$false
Did the trick.
Thanks for this. Its making my rollout of MFA a lot easier.
Hi Rudy,
Thank you for this excellent script. Is there a way I can run this against users who are members of an AAD group?
Thanks!
Hi Rudy,
I think I’ve figure it out.
Get-MsolGroup -SearchString “MyAADGroup”
Get-MsolGroupMember -GroupObjectId 374ae704-8425-4140-a270-9b8a05222510 | ForEach-Object { .\Get-MFAStatus.ps1 -UserPrincipalName $_.EmailAddress } | Export-CSV c:\temp\output.csv -noTypeInformation
Thanks again for this excellent resource.
I love this script, I took pieces of this and created a GUI for doing this. Since O365 only allows global admins the ability to manage MFA from users within the O365 admin window.
So I have a PowerShell GUI that will get Status, Enable, Disable, Enforce, Reset, Revoke, or Refresh. Thanks for this excellent guide.
More details on the GUI?
Hi all.
There was a previous comment on WHEN MFA was enabled. I generally use the RememberDevicesNotIssuedBefore value from the StrongAuthenticationRequirements attribute
Would there be a way to filter by a particular license? I am at a school and only do MFA for employees. The students have a different license and that is easiest way to differentiate. Thanks for a great script.
You will need to change line 211 and replace {$_.IsLicensed -eq $isLicensed} to
{($_.licenses).AccountSkuId -match "DEVELOPERPACK_E5"}
Change Developerpack_e5 to your license SKU:
Get-msolaccountsku
Amazing script, however for some reason it ignores all guest accounts. Am I missing something or it would requires a separate switch to be coded into the script, please?
add the parameter -Licenend or -Licenend:$false to get all user without license
-IsLicensed:$false
Most of our tenants have unlicensed global admins, they don’t show if I run it with -adminsOnly switch. Is there a way to run the report so it shows both licensed and unlicensed users on the same report?
Would be really great if the report included all users, licensed and unlicensed, and the licensed / unlicensed status was just another column that we could filter on in excel
Is there any way to include the sign-in methods for each user (Authenticator App, Phone, etc.), and also indicate which one is the Default Sign-in method?
I have added it in the last update. The report will show the default method and all configured methods for each user.
Any way to get the date that MFA was enabled on the accounts?
Nope, not that I can find.
Amazing, but it asks for auth every time you run it. My other script doesnt, it just reports after the initial PS auth logon. Can this be resolved?
I have updated the script. It will now check for an existing MSOL connection.
Is there an option to show if there are more methods used to setup MFA? For self service password reset we need two methods, but would like to see which persons have setup more than one method. Currently the script it only shows one method even if two or more methods have been added.
I have updated the script so it now lists all configured MFA types for each user.
I saved the file and I currently run it using the .\Get-MFAStatus.ps1. When I try to just run it directly from ISE, it will start running the program without allowing me to enter any parameters.
Is there a way to set this up where I can just run it like a regular command? Ideally I am trying to use this as a function that loads when I startup PowerShell and add it to a loop to do a check but it won’t work that way.
You will need to use your PowerShell Profile for this. I had an old article about that, but it was outdated. So just written a new one with all the details.
Hey Rudy
thanks for the script, its very helpful.
I’ve noticed an issue where it doesn’t identify the admins correctly, unfortunately my PowerShell skills are not good enough to actually fix it.
I found another script which does a great job of identifying the admins, but lacks the ability to determine the MFA status.
I have updated the script, it will now get all licensed users with a admin role and mark them correctly as admin.
Great script, thank you! We have a subset of users that are members of a NonMFAUsers group that are not required to use MFA. How would I use this script to export MFA Licensed/Disabled users, EXCEPT those that are members of our NonMFAUsers group?
You will need to get all the users first and then get the msol details. Something like this in line 205:
$group = Get-ADGroup NonMFAUsers
$MsolUsers = Get-ADUser -Properties memberof -filter 'enabled -eq $true' | Where-Object {$group.DistinguishedName -notin $_.memberof} | Get-MsolUser -UserPrincipalName $_.UserPrincipalName
Hi,
Great script, thanks alot! Just one thing that I noticed and I am not sure if it is by design or not. If a user has been enabled for MFA and then for whatever reason been disabled again the script will still return that user as enabled.
Is there an option to break this down based on say getting the status of a single user for checking for enabled / enforced / disabled? I am new to powershell and am looking at pulling info for single users
You can run it for a single user with:
Get-MFAStatus.ps1 -UserPrincipalName '[email protected]'
Hi All,
In my tenant i have different license types A1 till A5
i would like assistance whereas i can pull report of users that have mfa enforced on them and which license type a person has been assigned.
I have used this powershell command to retrieve information about mfa status
Connect-MsolService
$Users = Get-MsolUser -all
$Users | select DisplayName,Title,State,@{N=’Email’;E={$_.UserPrincipalName}},@{N=’StrongAuthenticationRequirements’;E={($_.StrongAuthenticationRequirements.State)}} | Export-Csv -NoTypeInformation C:\temp\Users.csv
but the issue is when i try to add license type no results found
You will need to use
Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "EnterprisePremium"}
. To get the correct accountSKuId you can lookup the license names with Get-MsolAccountSkuHi, Thanks for the automation script. I have one question, does this script reports the users that are enabled the MFA using conditional access policy?
No, it’s pretty difficult to get an accurate report of the MFA Status based on the conditional access. What you can do is add StrongAuthenticationUserDetails to the PSCustomobject:
MFADevice = $MsolUser.StrongAuthenticationMethods
This should list the device/method that the user has used to approve the MFA request. But as said, it’s not really accurate.
Nice script (Thanks!!) and produces a good amount of information for the analysis I am trying to do.
One problem is that it doesn’t return all the users – the environment I am working on has 1298 licensed users but only 939 show up in the Got MFA list when running this script… I switched it to return those without MFA and it came back with 139 users which doesn’t add up. The number of users with MFA plus the number without should add up to the actual number of licensed users in the environment… what am I missing?
Some History: We enabled MFA using “Security Defaults” an I’m suspicious that SD doesn’t work as well as one would expect….
Additionally, the -isadmin feature of this script doesn’t seem to work for me as it doesn’t report whether user is admin…. users that ARE admin don’t show up marked as admin
Andy, I ran into the same issue and was able to get around it by adjusting the “[int]$MaxResults = ” line. It is set to only return the top 1000 results by default so I adjusted it up to 10000 and was able to get full results in my tenant, though you may need to go higher depending on the size of your tenant. Can’t speak to the -isadmin feature though as I did not use that, however when I just ran the full report (the script with no options other than exporting to csv) it did accurately identify which accounts were admins in the report.
Get list of users who have registered their MFA and export it.
Get-MsolUser -All | where {$_.StrongAuthenticationMethods -ne $null} | Select-Object -Property UserPrincipalName | Sort-Object userprincipalname | Export-csv C:\temp\Filename.csv
I saved the script to c:\temp and ran it. Doesn’t appear to do anything and when I then do “Get-MFAStatus -withoutMFAonly it says the Get-MFAStatus is not recognized.
I also ran Get-MFAstatus.ps1 -withoutMFAonly and nothing happened.
Yes, this is a function, which I used in a PowerShell runbook. If you want to run the script standalone, then remove the function wrapper (First and last line from the script). Then you can just run Get-mfastatus.ps1
FYI, you need to run the script, which installs the function. THEN you can run the
get-mfastatus function.
Hello. I’ve made all steps. but, I have an error
Get-MFAStatus “is not recognized as the name of cmdlet, function, script file
or executable program.
Just refer to the file .\get-mfastatus.ps1.
What if MFA is enabled using conditional access policies and the user is part of that policy but StrongAuthenticationMethods for the user is false ? It will be reported as a false positive.
If you are using conditional access policies then you don’t need to force MFA. You can maybe alter the script to check if the user is a member of the conditional access policy.
Hi,
I’m connected with MsolService and try to start the script but nothing happened.
Did you have saved the script in a ps1 file? If you have saved it as GetMFAStatus.ps1 then you can call the script from PowerShell with
GetMFAStatus.ps1 -withOutMFAOnly
Where do we need to save this file?
I saved it to D:\try\MFAStatus.ps1
do I need to go into that directory and run the command?
Yes, just open PowerShell in that directory and run the script with the commands > MFAStatus.ps1 -withoutMFAOnly
I am getting this – PS C:\temp> MFAStatus.ps1 -withoutMFAOnly
MFAStatus.ps1 : The term ‘MFAStatus.ps1’ is not recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ MFAStatus.ps1 -withoutMFAOnly
+ ~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (MFAStatus.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Have you saved the script also in C:\temp? You can read more about running PowerShell scripts in this article.
I am running it from here – “C:\temp\MFAStatus.ps1”
And you have also saved the file in c:\temp?
Otherwise navigate to the folder and try:
.\MFAStatus.ps1
Got it working…thanks! Any tips to get account status in that report? I want to excluded blocked users.
This is pretty great, thank you. I’m attempting to get a list of users with a specific Strong Authentication Method Type set specifically to “PhoneAppNotification”. As it turns out, Microsoft offers users the ability to put their cell phone numbers on their accounts, which get registered as a Strong Authentication Method, even when MFA isnt configured. Because of that I have thousands of users that get returned when basic Strong Authentication queries are run.
Hi Jason,
You can use the following code to only list the users with PhoneAppNotification:
$msolUsers = get-msoluser -EnabledFilter EnabledOnly -MaxResults 1000
foreach ($MsolUser in $MsolUsers) {
$methodType = $MsolUser.StrongAuthenticationMethods | Where-Object {$_.IsDefault -eq $true} | Select-Object -ExpandProperty MethodType
# List only the user that don't have MFA enabled
if ($methodType -eq 'PhoneAppNotification') {
write-host $MsolUser.UserPrincipalName
}
}