Forum Discussion
Report on MFA Status with Conditional Access
- NidalTJul 08, 2022Brass Contributor
The way I have resolved this is by creating a Dynamic Azure AD Group that adds all users eligible for MFA via Conditional Access (e.g. having the correct license assigned).
Then scoped the Conditional Access policy to that group.
Then, for the inventory, I have Powershell script using MsGraph that will chcek to see if any Authentication Method exists for all users and what method it is.
In the same script, I cross-reference these users with the Azure AD Group membership for the group that's scoped for Conditional License).
If user has an Authentication Method configured and is member of the group, MFA is enabled and enforced.
If user has an Authentication Method configured and not a member of the group, MFA is not enforced.
If user does not have an Authentication Method configured but is a member of the group, MFA is enabled but not yet enforced (e.g. user didn't enroll yet).
If user is not a member of the group, MFA is disabled.
Now this all sounds too much. And it is.
It's unbelievable that we have to do all of this to be able to report on such a basic feature.
But I really didn't see any other way to have a reliable inventory in our environment for MFA.
I would share the script, but it's really fully customized for our own environment and it wouldn't be usefull for you.
It does a complete inventory of all users, guests, licenses, last login, mfa, etc...
But as I've said... it's specific to our environment and it would be useless to share it with anyone.
The MFA part is loosely based on this script:
https://github.com/admindroid-community/powershell-scripts/blob/master/Export%20MFA%20Status%20Report%20using%20MS%20Graph/GetMFAStatusReport.ps1
I took snippets of that script because it's very well written.
But if you use it as is, and add a few lines to get AAD Group membership, you would have the same.
- SimonBrownSep 25, 2022Copper Contributor
I've been using this script for a while but only this week realised that the reporting was incorrect.
I've just edited the script to be more accurate in a generic way. Hopefully this helps others.
Where the script originally 'checked' for Conditional Access, I replaced this
$MFAStatus='Enabled via Conditional Access'With this
$mfaPolicies = Get-AzureADMSConditionalAccessPolicy | Where {$_.GrantControls.BuiltInControls -contains "Mfa"} $aadUser = Get-AzureADUser -ObjectId $Upn $userObjectId = $aadUser.ObjectId $userMembership = ($aadUser | Get-AzureADUserMembership).ObjectId if (!$userMembership) { $userMembership = "" } if ($mfaPolicies | Where { $_.Conditions.Users.IncludeUsers -eq "All" -or ` $_.Conditions.Users.IncludeUsers -contains $aadUser.ObjectId -or ` (Compare-Object -ReferenceObject $_.Conditions.Users.IncludeGroups -DifferenceObject $userMembership -IncludeEqual -ErrorAction SilentlyContinue).SideIndicator -contains "==" -or ` (Compare-Object -ReferenceObject $_.Conditions.Users.IncludeRoles -DifferenceObject $userMembership -IncludeEqual -ErrorAction SilentlyContinue).SideIndicator -contains "==" -and ` $_.Conditions.Users.ExcludeUsers -notcontains $aadUser.ObjectId -or ` (Compare-Object -ReferenceObject $_.Conditions.Users.ExcludeGroups -DifferenceObject $userMembership -IncludeEqual -ErrorAction SilentlyContinue).SideIndicator -contains "==" -or ` (Compare-Object -ReferenceObject $_.Conditions.Users.ExcludeRoles -DifferenceObject $userMembership -IncludeEqual -ErrorAction SilentlyContinue).SideIndicator -contains "==" -and ` $_.State -eq "enabled" }) { $MFAStatus="Enabled via Conditional Access" } else { $MFAStatus="Disabled" }All it really does is get the current users ObjectID, get the ObjectID of all the roles and groups to which the user is assigned and then checks the conditional access policies which are configured for MFA to see if the user belongs to them, is not excluded from them, and the policy is enabled.
I had to use the AzureAD module to do this so I also have to authenticate with that module so I had to update the part of the script which connects to MSOnline to also connect to Azure AD by replacing this
if(($UserName -ne "") -and ($Password -ne "")) { $SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force $Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword Connect-MsolService -Credential $credential } else { Connect-MsolService | Out-Null }With this
if(($UserName -ne "") -and ($Password -ne "")) { $SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force $Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword Connect-MsolService -Credential $credential Connect-AzureAD -Credential $credential } else { Write-Host "You will be prompted to sign-in twice, once to Microsoft 365 and then for Azure AD!" -ForegroundColor Yellow Connect-MsolService | Out-Null Connect-AzureAD | Out-Null }The issue seems to be that the script writer assumed that not explicitly enabling/enforcing MFA for a user meant that it was "Enabled via Conditional Access" and hard coded that value. This should have been "Controlled via Conditional Access", but it never meant a policy was actually applied.
UPADTE: These changes do cause the script to throw errors when a user is not a member of any roles/groups. They are nothing to worry about and the script is still accurate according to my testing. I'll try and figure out how to suppress them without making it really complicated.
UPDATE: Added a quick if statement to check if `$userMembership` is null, if it is then it's created as a blank variable which doesn't result in an error for the `compare-object`.
- NidalTSep 25, 2022Brass ContributorThis is gold!
I didn't think of doing it that way. It makes much more sense!
Thank you!
I'll review my script and update it with your part.
- justJustinianJul 11, 2022Copper ContributorI appreciate everyone's feedback. Now to get better built-in reporting, but this is great, thank you!
- Tim_BixleyJul 07, 2022Copper Contributor
justJustinian
So far I've seen 2 methods used.1. You can report on the MFA registration type, so if you have simple conditional access policies you may be able to assume coverage if they are registered.
2. I've seen some third party tools actually parse the login audit logs and report on any logins without MFA.
But no, nothing direct from MS.