Get MFA Status of Office 365 users with PowerShell

Source: https://lazyadmin.nl/powershell/list-office365-mfa-status-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.

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

Close Menu