Entra / Microsoft 365 · Users & guests
Report non-MFA sign-ins
A script to show how to use the Microsoft Graph PowerShell SDK to report on non-MFA sign-ins in Microsoft 365.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -Scopes "AuditLog.Read.All"
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $StartDate = (Get-Date $Item.CreatedDateTime).toString('yyyy-MM-ddT00:00:00Z'),[string] $EndDate = (Get-Date $Item.CreatedDateTime).toString('yyyy-MM-ddT23:59:59Z'))Connect-MgGraph -Scopes "AuditLog.Read.All"$Uri = 'https://graph.microsoft.com/beta/reports/authenticationMethods/userMfaSignInSummary'[array]$Data = Invoke-MgGraphRequest -Uri $Uri -Method Get -OutputType PSObject | Select-Object -ExpandProperty ValueIf ($Data) {Write-Output "Processing MFA summary sign-in data"} Else {Write-Output "No non-MFA sign-ins found" -ForegroundColor GreenBreak}$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($Item in $Data) {$NonMFAUsers = @()$NonMFAApps = @()If ($Item.singleFactorSignIns -gt 0) {Write-Host ("Checking sign-in records from {0} to {1}" -f $StartDate, $EndDate)[array]$SignInRecords = Get-MgBetaAuditLogSignIn -Filter "createdDateTime gt $StartDate and createdDateTime lt $EndDate and AuthenticationRequirement eq 'singleFactorAuthentication' and status/errorCode eq 0" -Sort "createdDateTime DESC"If ($SignInRecords.Count -gt 0) {Write-Host ("Found {0} non-MFA sign-in records for {1}" -f $SignInRecords.Count, (Get-Date $Item.CreatedDateTime -format 'dd-MMM-yyyy'))[array]$SignInRecords = $SignInRecords | Sort-Object CreatedDate[array]$NonMFAUsers = $SignInRecords | Group-Object UserPrincipalName -NoElement | Select-Object -ExpandProperty Name[array]$NonMFAApps = $SignInRecords | Group-Object AppDisplayName -NoElement | Select-Object -ExpandProperty Name} Else {Write-Host "No non-MFA sign-in records found" -ForegroundColor Green}}$ReportLine = [PSCustomObject][Ordered]@{Date = Get-Date $Item.CreatedDateTime -format 'dd-MMM-yyyy''Total Signins' = $Item.TotalSignIns'Non MFA' = $Item.singleFactorSignIns'MFA Signins' = $Item.multiFactorSignIns'Non MFA Percentage' = "{0:P2}" -f ($Item.singleFactorSignIns / $Item.TotalSignIns)'Non MFA Users' = $NonMFAUsers -Join ", "'Non MFA Apps' = $NonMFAApps -Join ", "}$Report.Add($ReportLine)}$Report | Out-GridView -Title "Non-MFA Sign-In Report"Write-Host "Generating an Excel or CSV report for non-MFA sign-ins"# Generate reportsIf (Get-Module ImportExcel -ListAvailable) {$ExcelGenerated = $True$ExcelTitle = ("Non-MFA sign-ins for period {0} to {1}" -f $StartDate, $EndDate)Import-Module ImportExcel -ErrorAction SilentlyContinue$OutputXLSXFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\NonMFASignIns.xlsx"If (Test-Path $OutputXLSXFile) {Remove-Item $OutputXLSXFile -ErrorAction SilentlyContinue}$Report | Export-Excel -Path $OutputXLSXFile -WorksheetName "Non-MFA Sign-Ins" -Title $ExcelTitle -TitleBold -TableName "NonMFASignIns" -AutoSize} Else {$OutputCSVFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\NonMFASignIns.csv"$Report | Export-Csv -Path $OutputCSVFile -NoTypeInformation -Encoding Utf8}If ($ExcelGenerated) {Write-Host ("An Excel worksheet containing the report data is available in {0}" -f $OutputXLSXFile)} Else {Write-Host ("A CSV file containing the report data is available in {0}" -f $OutputCSVFile)}
Parameters
ParameterDefaultNotes
-StartDate(Get-Date $Item.CreatedDateTime).toString('yyyy-MM-ddT00:00:00Z')Start of the reporting window.-EndDate(Get-Date $Item.CreatedDateTime).toString('yyyy-MM-ddT23:59:59Z')End of the reporting window.Attribution
Author
Office365itpros