From 2cf3fec68c802f8df326a712c4d3c663cdcb3102 Mon Sep 17 00:00:00 2001 From: AdminDroid <49208841+admindroid-community@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:21:40 +0530 Subject: [PATCH] Export Per-user MFA Status using MS Graph --- .../CheckMFAStatus.ps1 | 257 ++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 Check Per-user MFA Status using MS Graph/CheckMFAStatus.ps1 diff --git a/Check Per-user MFA Status using MS Graph/CheckMFAStatus.ps1 b/Check Per-user MFA Status using MS Graph/CheckMFAStatus.ps1 new file mode 100644 index 0000000..01ac0c1 --- /dev/null +++ b/Check Per-user MFA Status using MS Graph/CheckMFAStatus.ps1 @@ -0,0 +1,257 @@ +<# +============================================================================================= +Name: Export MFA status Microsoft Graph PowerShell +Description: This script exports Microsoft 365 users' per-user MFA status report to CSV file +Version: 1.0 +Website: blog.admindroid.com + + +Script Highlights : +~~~~~~~~~~~~~~~~~ + +1.Generates 5+ MFA status reports +2.Helps to filter and find MFA enabled users +3.Identifies MFA disabled users +4.Helps to track MFA enforced users +5.Exports MFA status report for licensed users alone +6.Checks MFA status for sign-in allowed users alone +7.Helps to generate more granular MFA reports by combining multiple filtering params. +8.The script uses MS Graph PowerShell and installs MS Graph Beta PowerShell SDK (if not installed already) upon your confirmation. +9.The script can be executed with an MFA enabled account too. +10.Exports report results as a CSV file. +11.The script is scheduler friendly. +12.It can be executed with certificate-based authentication (CBA) too. + +For detailed script execution: https://blog.admindroid.com/export-mfa-status-report-for-entra-id-accounts-using-powershell +============================================================================================ +#> +Param +( + [Parameter(Mandatory = $false)] + [switch]$CreateSession, + [switch]$MFAEnabledUsersOnly, + [switch]$MFADisabledUsersOnly, + [switch]$MFAEnforcedUsersOnly, + [switch]$LicensedUsersOnly, + [switch]$SignInAllowedUsersOnly, + [string]$TenantId, + [string]$ClientId, + [string]$CertificateThumbprint + +) +Function Connect_MgGraph +{ + #Check for module installation + $MsGraphBetaModule = Get-Module Microsoft.Graph.Beta -ListAvailable + if($MsGraphBetaModule -eq $null) + { + Write-host "Important: Microsoft Graph Beta module is unavailable. It is mandatory to have this module installed in the system to run the script successfully." + $confirm = Read-Host Are you sure you want to install Microsoft Graph Beta module? [Y] Yes [N] No + if($confirm -match "[Y]") + { + Write-host "Installing Microsoft Graph Beta module..." + Install-Module Microsoft.Graph.Beta -Scope CurrentUser -AllowClobber + Write-host "Microsoft Graph Beta module is installed in the machine successfully" -ForegroundColor Magenta + } + else + { + Write-host "Exiting. `nNote: Microsoft Graph Beta module must be available in your system to run the script" -ForegroundColor Red + Exit + } + } + #Disconnect Existing MgGraph session + if($CreateSession.IsPresent) + { + Disconnect-MgGraph + } + #Connecting to MgGraph beta + Write-Host Connecting to Microsoft Graph... + if(($TenantId -ne "") -and ($ClientId -ne "") -and ($CertificateThumbprint -ne "")) + { + Connect-MgGraph -TenantId $TenantId -AppId $ClientId -CertificateThumbprint $CertificateThumbprint -NoWelcome + } + else + { + Connect-MgGraph -Scopes "User.Read.All","UserAuthenticationMethod.Read.All","Policy.ReadWrite.AuthenticationMethod" -NoWelcome + } +} +Connect_MgGraph + + +$ProcessedUserCount=0 +$ExportCount=0 + #Set output file + $Location=Get-Location + $ExportCSV="$Location\MfaStatusReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv" + $Result="" + $Results=@() + +#Get all users +Get-MgBetaUser -All | foreach { + $ProcessedUserCount++ + $Name= $_.DisplayName + $UPN=$_.UserPrincipalName + $Department=$_.Department + $UserId=$_.Id + if($_.AccountEnabled -eq $true) + { + $SigninStatus="Allowed" + } + else + { + $SigninStatus="Blocked" + } + if(($_.AssignedLicenses).Count -ne 0) + { + $LicenseStatus="Licensed" + } + else + { + $LicenseStatus="Unlicensed" + } + $Is3rdPartyAuthenticatorUsed="False" + $MFAPhone="-" + $MicrosoftAuthenticatorDevice="-" + Write-Progress -Activity "`n Processed users count: $ProcessedUserCount "`n" Currently processing user: $Name" + [array]$MFAData=Get-MgBetaUserAuthenticationMethod -UserId $UPN + $AuthenticationMethod=@() + $AdditionalDetails=@() + + foreach($MFA in $MFAData) + { + Switch ($MFA.AdditionalProperties["@odata.type"]) + { + "#microsoft.graph.passwordAuthenticationMethod" + { + $AuthMethod = 'PasswordAuthentication' + $AuthMethodDetails = $MFA.AdditionalProperties["displayName"] + } + "#microsoft.graph.microsoftAuthenticatorAuthenticationMethod" + { # Microsoft Authenticator App + $AuthMethod = 'AuthenticatorApp' + $AuthMethodDetails = $MFA.AdditionalProperties["displayName"] + $MicrosoftAuthenticatorDevice=$MFA.AdditionalProperties["displayName"] + } + "#microsoft.graph.phoneAuthenticationMethod" + { # Phone authentication + $AuthMethod = 'PhoneAuthentication' + $AuthMethodDetails = $MFA.AdditionalProperties["phoneType", "phoneNumber"] -join ' ' + $MFAPhone=$MFA.AdditionalProperties["phoneNumber"] + } + "#microsoft.graph.fido2AuthenticationMethod" + { # FIDO2 key + $AuthMethod = 'Passkeys(FIDO2)' + $AuthMethodDetails = $MFA.AdditionalProperties["model"] + } + "#microsoft.graph.windowsHelloForBusinessAuthenticationMethod" + { # Windows Hello + $AuthMethod = 'WindowsHelloForBusiness' + $AuthMethodDetails = $MFA.AdditionalProperties["displayName"] + } + "#microsoft.graph.emailAuthenticationMethod" + { # Email Authentication + $AuthMethod = 'EmailAuthentication' + $AuthMethodDetails = $MFA.AdditionalProperties["emailAddress"] + } + "microsoft.graph.temporaryAccessPassAuthenticationMethod" + { # Temporary Access pass + $AuthMethod = 'TemporaryAccessPass' + $AuthMethodDetails = 'Access pass lifetime (minutes): ' + $MFA.AdditionalProperties["lifetimeInMinutes"] + } + "#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod" + { # Passwordless + $AuthMethod = 'PasswordlessMSAuthenticator' + $AuthMethodDetails = $MFA.AdditionalProperties["displayName"] + } + "#microsoft.graph.softwareOathAuthenticationMethod" + { + $AuthMethod = 'SoftwareOath' + $Is3rdPartyAuthenticatorUsed="True" + } + + } + $AuthenticationMethod +=$AuthMethod + if($AuthMethodDetails -ne $null) + { + $AdditionalDetails +="$AuthMethod : $AuthMethodDetails" + } + } + #To remove duplicate authentication methods + $AuthenticationMethod =$AuthenticationMethod | Sort-Object | Get-Unique + $AuthenticationMethods= $AuthenticationMethod -join "," + $AdditionalDetail=$AdditionalDetails -join ", " + $Print=1 + #Per-user MFA status + $MFAStatus=(Invoke-MgGraphRequest -Method GET -Uri "/beta/users/$UserId/authentication/requirements").perUserMfaState + <# [array]$StrongMFAMethods=("Fido2","PhoneAuthentication","PasswordlessMSAuthenticator","AuthenticatorApp","WindowsHelloForBusiness") + $MFAStatus="Disabled" + + + foreach($StrongMFAMethod in $StrongMFAMethods) + { + if($AuthenticationMethod -contains $StrongMFAMethod) + { + $MFAStatus="Strong" + break + } + } + + if(($MFAStatus -ne "Strong") -and ($AuthenticationMethod -contains "SoftwareOath")) + { + $MFAStatus="Weak" + } #> + + #Filter result based on MFA status + if($MFADisabledUsersOnly.IsPresent -and $MFAStatus -ne "disabled") + { + $Print=0 + } + if($MFAEnabledUsersOnly.IsPresent -and $MFAStatus -ne "enabled") + { + $Print=0 + } + if($MFAEnforcedUsersOnly.IsPresent -and $MFAStatus -ne "enforced") + { + $Print=0 + } + + #Filter result based on license status + if($LicensedUsersOnly.IsPresent -and ($LicenseStatus -eq "Unlicensed")) + { + $Print=0 + } + + #Filter result based on signin status + if($SignInAllowedUsersOnly.IsPresent -and ($SigninStatus -eq "Blocked")) + { + $Print=0 + } + + if($Print -eq 1) + { + $ExportCount++ + $Result=@{'Name'=$Name;'UPN'=$UPN;'Department'=$Department;'License Status'=$LicenseStatus;'SignIn Status'=$SigninStatus;'Registered Authentication Methods'=$AuthenticationMethods;'Per-user MFA Status'=$MFAStatus;'MFA Phone'=$MFAPhone;'Microsoft Authenticator Configured Device'=$MicrosoftAuthenticatorDevice;'Is 3rd-Party Authenticator Used'=$Is3rdPartyAuthenticatorUsed;'Additional Details'=$AdditionalDetail} + $Results= New-Object PSObject -Property $Result + $Results | Select-Object Name,UPN,'Per-user MFA Status',Department,'License Status','SignIn Status','Registered Authentication Methods','MFA Phone','Microsoft Authenticator Configured Device','Is 3rd-Party Authenticator Used','Additional Details' | Export-Csv -Path $ExportCSV -Notype -Append + } +} + +if((Test-Path -Path $ExportCSV) -eq "True") + { + Write-Host `nThe exported report contains $ExportCount users. + Write-Host `nPer-user MFA status report available in: -NoNewline -Foregroundcolor Yellow; Write-Host $ExportCSV + Write-Host `n~~ Script prepared by AdminDroid Community ~~`n -ForegroundColor Green + Write-Host "~~ Check out " -NoNewline -ForegroundColor Green; Write-Host "admindroid.com" -ForegroundColor Yellow -NoNewline; Write-Host " to get access to 1800+ Microsoft 365 reports. ~~" -ForegroundColor Green `n`n + $Prompt = New-Object -ComObject wscript.shell + $UserInput = $Prompt.popup("Do you want to open output file?",` + 0,"Open Output File",4) + If ($UserInput -eq 6) + { + Invoke-Item "$ExportCSV" + } + } + else + { + Write-Host No users found. + } + \ No newline at end of file