Get MFA Status of Office 365 users with PowerShell

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 MFA Status PowerShell

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 'johndoe@contoso.com'

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.
<#
  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
#>
[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:

133 thoughts on “Get MFA Status of Office 365 users with PowerShell”

  1. I took this script and converted it to a powershell gui app that does the following

    Checks m.f.a status
    Enable m.f.a
    Disable m.f.a
    Enforce m.f.a
    Reset m.f.a
    Revoke m.f.a

  2. Hello Ruud,

    hope you doing well..!!!

    It was a nice script and helped a lot, however, it gave me results for a 9K+ account, we have around 100K+ IDs. Could you please help me with a parameter which helps to fetch data for all id’s?

    Also, MSOl is deprecated do you have a script with MgGraph? I read somewhere you are working on that

  3. 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.

  4. 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!

  5. 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?

  6. 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.

  7. 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:

            Get-MsolUser -UserPrincipalName user@domain.com | select -expandproperty StrongAuthenticationUserDetails
            

            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.

  8. 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?

  9. 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.

  10. I 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 ‘user@domain.com’ (the user that I noticed missing) I can see his information.

    So it works, but not completely. 🙂 Not sure what I am missing. 🙁

    • 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

  11. 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

    • 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.

  12. 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 😉

  13. 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.

  14. 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.

      • 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

  15. 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

  16. 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 lazyadmin@lazydev.onmicrosoft.com
      $MsolUser.StrongAuthenticationMethods

    • 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.

  17. 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.

  18. 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.

  19. 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?

  20. 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”

  21. 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!

  22. 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?

  23. 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.

  24. 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.

  25. Hi all.

    There was a previous comment on WHEN MFA was enabled. I generally use the RememberDevicesNotIssuedBefore value from the StrongAuthenticationRequirements attribute

  26. 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

  27. 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?

  28. 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

  29. 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?

  30. 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?

  31. 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.

  32. 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.

  33. 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.

  34. 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

  35. 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.

  36. 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

  37. 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-MsolAccountSku

  38. Hi, 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.

  39. 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.

  40. 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

  41. 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

  42. FYI, you need to run the script, which installs the function. THEN you can run the
    get-mfastatus function.

  43. 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.

  44. 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.

    • 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

    • 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

  45. 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
      }
      }

Leave a Comment

0 Shares
Tweet
Pin
Share
Share