Establish ongoing monitoring to track MFA adoption and identify users who disable or remove their authentication methods. This is crucial for maintaining security posture as you approach the 2026 compliance deadlines.
Create a monitoring script that can be scheduled to run weekly:
# MFA-Monitor.ps1
# Weekly MFA status monitoring with email alerts
param(
[string]$SMTPServer = "smtp.office365.com",
[string]$From = "mfa-monitor@yourdomain.com",
[string]$To = "security-team@yourdomain.com",
[string]$ReportPath = "C:\Reports\Weekly-MFA-Monitor.csv"
)
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "UserAuthenticationMethod.Read.All" -NoWelcome
# Get current MFA status
$users = Get-MgUser -All -Property DisplayName,UserPrincipalName,Id,AccountEnabled,CreatedDateTime
$currentResults = @()
foreach ($user in $users) {
if ($user.AccountEnabled) {
$authMethods = Get-MgUserAuthenticationMethod -UserId $user.Id -ErrorAction SilentlyContinue
$mfaCapable = $false
$methodCount = 0
if ($authMethods) {
foreach ($method in $authMethods) {
$methodType = $method.AdditionalProperties["@odata.type"]
if ($methodType -in @(
"#microsoft.graph.microsoftAuthenticatorAuthenticationMethod",
"#microsoft.graph.phoneAuthenticationMethod",
"#microsoft.graph.fido2AuthenticationMethod",
"#microsoft.graph.softwareOathAuthenticationMethod",
"#microsoft.graph.windowsHelloForBusinessAuthenticationMethod"
)) {
$mfaCapable = $true
$methodCount++
}
}
}
$currentResults += [PSCustomObject]@{
UserPrincipalName = $user.UserPrincipalName
DisplayName = $user.DisplayName
MFACapable = $mfaCapable
MethodCount = $methodCount
CheckDate = Get-Date -Format "yyyy-MM-dd"
}
}
}
# Compare with previous week's results if available
$previousReportPath = $ReportPath -replace "\.csv$", "-Previous.csv"
$newIssues = @()
$resolvedIssues = @()
if (Test-Path $previousReportPath) {
$previousResults = Import-Csv $previousReportPath
# Find users who lost MFA capability
foreach ($current in $currentResults) {
$previous = $previousResults | Where-Object {$_.UserPrincipalName -eq $current.UserPrincipalName}
if ($previous -and $previous.MFACapable -eq "True" -and $current.MFACapable -eq $false) {
$newIssues += "$($current.DisplayName) ($($current.UserPrincipalName)) lost MFA capability"
}
}
# Find users who gained MFA capability
foreach ($current in $currentResults) {
$previous = $previousResults | Where-Object {$_.UserPrincipalName -eq $current.UserPrincipalName}
if ($previous -and $previous.MFACapable -eq "False" -and $current.MFACapable -eq $true) {
$resolvedIssues += "$($current.DisplayName) ($($current.UserPrincipalName)) enabled MFA"
}
}
}
# Export current results
$currentResults | Export-Csv -Path $ReportPath -NoTypeInformation
# Archive previous results
if (Test-Path $ReportPath) {
Copy-Item $ReportPath $previousReportPath -Force
}
# Send email alert if there are issues
if ($newIssues.Count -gt 0 -or $resolvedIssues.Count -gt 0) {
$emailBody = @"
Weekly MFA Status Update
========================
New MFA Issues ($($newIssues.Count)):
$($newIssues -join "`n")
Resolved Issues ($($resolvedIssues.Count)):
$($resolvedIssues -join "`n")
Current Statistics:
Total Active Users: $($currentResults.Count)
MFA Capable: $(($currentResults | Where-Object {$_.MFACapable -eq $true}).Count)
Non-MFA Users: $(($currentResults | Where-Object {$_.MFACapable -eq $false}).Count)
Report generated: $(Get-Date)
"@
# Send email (requires configured SMTP)
try {
Send-MailMessage -SmtpServer $SMTPServer -From $From -To $To -Subject "Weekly MFA Status Alert" -Body $emailBody
Write-Host "Alert email sent successfully" -ForegroundColor Green
}
catch {
Write-Warning "Failed to send email alert: $($_.Exception.Message)"
}
}
Disconnect-MgGraph
Schedule this script to run weekly using Windows Task Scheduler:
# Create scheduled task for weekly MFA monitoring
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\MFA-Monitor.ps1"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 9:00AM
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount
Register-ScheduledTask -TaskName "Weekly MFA Status Monitor" -Action $action -Trigger $trigger -Settings $settings -Principal $principal
Warning: Remember that the October 2026 deadline for Azure portal MFA enforcement is approaching. Users without MFA will lose access to Azure resources, so proactive monitoring is essential.
Verification: Test the monitoring script manually first, then check that the scheduled task appears in Task Scheduler and runs successfully on the designated schedule.