Identify Admin Users Without MFA Enabled Using Graph PowerShell

Multi-Factor Authentication (MFA) remains the strongest baseline security control for protecting privileged accounts in Microsoft 365. Admin accounts without MFA pose a significant security risk and are considered one of the top identity vulnerabilities in any organization.

This Graph PowerShell script identifies only those admin accounts that do not have MFA enabled, compiles their assigned roles, and emails the complete report to the administrator for immediate attention.

🚀 Community Edition Released!

Try the M365Corner Microsoft 365 Reporting Tool — your DIY pack with 20+ out-of-the-box M365 reports for Users, Groups, and Teams.


i) The Script

$AdminUPN = "admin@yourtenant.onmicrosoft.com"
Connect-MgGraph -Scopes "Directory.Read.All","User.Read.All","Mail.Send"
$Roles = Get-MgDirectoryRole -All
$AdminsWithoutMFA = @{}

foreach ($role in $Roles) {
    try {
        $Members = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All
    } catch {
        continue
    }

    foreach ($member in $Members) {

        if ($member.AdditionalProperties.'@odata.type' -ne "#microsoft.graph.user") { continue }

        $UserId = $member.Id

        if (-not $AdminsWithoutMFA.ContainsKey($UserId)) {
            try {
                $User = Get-MgUser -UserId $UserId -Property DisplayName,UserPrincipalName,AccountEnabled
            } catch {
                continue
            }

            try {
                $AuthMethods = Get-MgUserAuthenticationMethod -UserId $UserId
            } catch {
                continue
            }

            $MFAEnabled = $false

            foreach ($method in $AuthMethods) {
                switch ($method.AdditionalProperties.'@odata.type') {
                   "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod" { $MFAEnabled = $true }
                   "#microsoft.graph.fido2AuthenticationMethod"                   { $MFAEnabled = $true }
                   "#microsoft.graph.phoneAuthenticationMethod"                  { $MFAEnabled = $true }
                   "#microsoft.graph.windowsHelloForBusinessAuthenticationMethod" { $MFAEnabled = $true }
                   "#microsoft.graph.temporaryAccessPassAuthenticationMethod"    { $MFAEnabled = $true }
                }
            }

            if (-not $MFAEnabled) {
                $AdminsWithoutMFA[$UserId] = @{
                    DisplayName         = $User.DisplayName
                    UserPrincipalName   = $User.UserPrincipalName
                    AccountEnabled      = $User.AccountEnabled
                    AdminRoles          = @($role.DisplayName)
                }
            }

        } else {
            $AdminsWithoutMFA[$UserId].AdminRoles += $role.DisplayName
        }
    }
}

$Report = $AdminsWithoutMFA.Values | ForEach-Object {
    [PSCustomObject]@{
        "Admin Name"         = $_.DisplayName
        "User Principal Name"= $_.UserPrincipalName
        "Account Enabled"    = if ($_.AccountEnabled) { "Enabled" } else { "Disabled" }
        "Assigned Roles"     = ($_.AdminRoles -join ", ")
        "MFA Status"         = "Disabled"
    }
}

$ReportPath = "$env:TEMP\Admins_Without_MFA.csv"
$Report | Export-Csv -Path $ReportPath -NoTypeInformation -Encoding UTF8

$Count = @($Report).Count
$Subject = "Admins Without MFA Enabled — $(Get-Date -Format 'yyyy-MM-dd')"

$Body = @"
Hello Admin,<br><br>
Attached is the latest <b>Admins Without MFA Enabled</b> report.<br>
Total Admin Accounts With MFA Disabled: <b>$Count</b><br><br>
It is strongly recommended to enforce MFA for these accounts.<br><br>
Regards,<br>
Graph PowerShell Script
"@

$AttachmentContent = [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes($ReportPath))

$Attachments = @(
    @{
        "@odata.type" = "#microsoft.graph.fileAttachment"
        Name          = [System.IO.Path]::GetFileName($ReportPath)
        ContentBytes  = $AttachmentContent
    }
)

$Message = @{
    Message = @{
        Subject = $Subject
        Body = @{
            ContentType = "HTML"
            Content     = $Body
        }
        ToRecipients = @(
            @{ EmailAddress = @{ Address = $AdminUPN } }
        )
        Attachments = $Attachments
    }
    SaveToSentItems = "true"
}

Send-MgUserMail -UserId $AdminUPN -BodyParameter $Message
Write-Host "Admins without MFA report emailed successfully to $AdminUPN" -ForegroundColor Green
                                

ii) How the Script Works

  1. Connects to Microsoft Graph
  2. The script authenticates with delegated Graph scopes:

    • Directory.Read.All – to read roles and user accounts
    • User.Read.All – to retrieve each user’s directory properties
    • Mail.Send – to email the final report

    These permissions must be granted with admin consent.

  3. Retrieves All Activated Directory Roles
  4. The script pulls all active directory roles (e.g., Global Admin, SharePoint Admin, Teams Admin, Exchange Admin).

    Each role is then processed individually.

  5. Identifies Actual User Objects
  6. Members of directory roles may include:

    • Users
    • Groups
    • Service principals

    The script processes only user objects by checking their @odata.type.

  7. Determines Whether MFA Is Enabled
  8. The script calls:

    Get-MgUserAuthenticationMethod

    This returns each authentication method registered for the user, such as:

    • Authenticator App
    • Phone (SMS/Voice)
    • FIDO2 keys
    • Temporary Access Pass
    • Windows Hello for Business

    The script marks MFA as enabled if any supported MFA-capable method exists.
Otherwise → MFA Disabled.

    Only users with zero MFA authentication methods are collected.

  9. Builds a Final MFA-Disabled Admin Report
  10. For each admin, the report includes:

    • Admin Name
    • User Principal Name
    • Account enabled/disabled
    • All assigned admin roles
    • MFA Status (always “Disabled”)
  11. Generates and Emails a CSV Report
  12. The script:

    1. Exports the collected data to a CSV
    2. Creates a Base64-encoded file attachment
    3. Sends the email using Send-MgUserMail
    4. Saves the message in Sent Items

    This ensures consistent reporting and easy compliance checks.


iii) Further Enhancements

Here are enhancements administrators frequently implement:

  • Include User Last Sign-In Activity
  • Add SignInActivity fields to see whether the admin actually logs in.

  • Notify Administrators via Teams Webhook
  • Send a Teams notification whenever MFA-disabled accounts are found.

  • Upload the CSV to SharePoint
  • Store historical MFA audit logs automatically.

  • Highlight Disabled Admin Accounts Separately
  • Identify accounts that are disabled but still assigned administrator roles.

  • Trigger Conditional Access Enforcement
  • Integrate with CA policies for remediation workflows.


iv) Possible Errors & Solutions

Error Cause Solution
403 Forbidden – accessDenied Insufficient privileges to read authentication methods. Sign in as:
  • Global Administrator
  • Privileged Authentication Administrator
  • Authentication Administrator
  • Security Administrator
Also ensure permission:
UserAuthenticationMethod.Read.All
has admin consent.
User Has No Authentication Methods but Still Appears Enabled Some organizations use legacy MFA methods not represented in authentication methods. Switch to fully modern MFA registration.
Email Sending Fails AdminUPN mailbox does not exist or is unlicensed. Use a mailbox-enabled account for sending email.
Script Returns Empty Report All admins have MFA enabled
No activated directory roles
Graph throttling
Validate MFA registration or retry after throttling cooldown.


v) Conclusion

This script delivers a high-impact security audit by identifying administrator accounts without MFA enabled—one of the biggest security gaps in Microsoft 365 environments. Automating this report ensures ongoing visibility and proactively reduces identity risk. With email delivery baked in, administrators get timely insights without having to run manual checks, strengthening your overall security posture.


Graph PowerShell Explorer Widget

20 Graph PowerShell cmdlets with easily accessible "working" examples.


Permission Required

Example:


                


                


                

© m365corner.com. All Rights Reserved. Design by HTML Codex