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

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 there 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 enable 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).

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.

Get more stuff like this

IT, Office365, Smart Home, PowerShell and Blogging Tips

I hate spam to, so you can unsubscribe at any time.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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