🔧 New: User Management Graph PowerShell Toolkit

Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more — all from one place.

🚀 Launch Toolkit

Identify MFA-Disabled Users in Microsoft 365 Using Graph PowerShell

While enabling Multi-Factor Authentication (MFA) is a top security priority, monitoring which users haven’t activated MFA is just as important. A single MFA-disabled account can become an entry point for attackers.

This article walks you through a Graph PowerShell script that fetches and displays only the users who have not enabled MFA in your Microsoft 365 tenant — all without relying on beta endpoints or legacy modules.

The Script: : List MFA-Disabled Users from Audit Logs

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "AuditLog.Read.All", "User.Read.All", "Directory.Read.All"

# Get list of users who have enabled MFA from audit logs
$uri = "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits" +
       "?`$filter=activityDisplayName eq 'Enable Strong Authentication'" +
       "&`$orderby=activityDateTime desc"

$response = Invoke-MgGraphRequest -Method GET -Uri $uri

# Extract UPNs of MFA-enabled users from audit logs
$mfaAuditRecords = $response.value | Where-Object { $_.targetResources -and $_.targetResources[0].userPrincipalName }
$mfaEnabledUPNs = @{}
foreach ($record in $mfaAuditRecords) {
    $upn = $record.targetResources[0].userPrincipalName
    if (-not $mfaEnabledUPNs.ContainsKey($upn)) {
        $mfaEnabledUPNs[$upn] = $true
    }
}

# Get all users in the tenant
$allUsers = Get-MgUser -All -Property UserPrincipalName, AccountEnabled, AssignedLicenses, Department

# Filter users who are NOT in the MFA-enabled list
$mfaDisabledUsers = $allUsers | Where-Object { -not $mfaEnabledUPNs.ContainsKey($_.UserPrincipalName) }

# Prepare results
$results = foreach ($user in $mfaDisabledUsers) {
    [PSCustomObject]@{
        'UserPrincipalName' = $user.UserPrincipalName
        'MFA Activated'     = "No"
        'License Status'    = if ($user.AssignedLicenses.Count -gt 0) { "Licensed" } else { "Unlicensed" }
        'Department'        = $user.Department
        'Sign In Status'    = if ($user.AccountEnabled) { "Allowed" } else { "Denied" }
    }
}

# Display result
if ($results.Count -eq 0) {
    Write-Host "All users in the tenant have MFA enabled." -ForegroundColor Green
} else {
    $results | Sort-Object UserPrincipalName | Format-Table -AutoSize
}

                            

How the Script Works

  • Connects to Microsoft Graph
  • The script uses:
    • AuditLog.Read.All
    • User.Read.All
    • Directory.Read.All
    • These scopes are required to query audit logs and user profiles.
  • Pulls Audit Logs
  • It queries the /auditLogs/directoryAudits endpoint for this activity: activityDisplayName eq 'Enable Strong Authentication'
    This logs when a user enables MFA.
  • Filters Non-MFA Users
    • Extracts UPNs from MFA audit logs
    • Retrieves all users in the tenant
    • Filters users not present in the MFA-enabled UPN list
  • Displays the Result
  • The script builds a clean report with:
    • UserPrincipalName
    • MFA Activated (set to "No")
    • License Status
    • Department
    • Sign In Status

Further Enhancements

Here’s how you can take this script further:

  • Exporting to CSV
  • $results | Export-Csv -Path "MFA-DisabledUsers.csv" -NoTypeInformation
  • Filter by Join Date
  • Filter users created in the past 30/90 days to spot new hires without MFA.

  • Email Alerts
  • Combine this script with Send-MailMessage to auto-notify IT teams of any new MFA-disabled accounts.

  • Group Filtering
  • Add filtering to scope the result to specific departments, locations, or roles.


Possible Errors & Solutions

Error Cause Solution
Access Denied Insufficient Graph permissions Ensure AuditLog.Read.All, User.Read.All, and Directory.Read.All are granted
NullReferenceException when accessing targetResources Some audit records may lack userPrincipalName Add checks to skip such entries
Variable reference is not valid: $_ Improper use inside strings Use "$($upn): $($_)" for safe error messaging
Script returns no results All users have MFA enabled, or audit data is incomplete Test against known MFA-disabled accounts or extend date range

Use Cases

This script is incredibly useful for:

  • Security Teams: Identify at-risk users who haven’t activated MFA.
  • Compliance Reporting : Prove enforcement of MFA across the org.
  • Proactive Risk Management: Prevent breaches before they happen
  • New Hire Auditing: Spot onboarding gaps where MFA hasn’t been configured.
  • Dashboard Integrations: Feed the results into Power BI or Excel for ongoing monitoring.

Conclusion

Detecting users who have not enabled MFA is just as important as confirming those who have. This Graph PowerShell script provides a fast and reliable way to identify these users by analyzing audit logs — without relying on preview APIs or external tools.

By running this audit regularly, you can stay ahead of threats and maintain tight identity security controls across your Microsoft 365 environment.


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