public/entraid/Get-EidUserMfaPolicy.ps1
function Get-EidUserMfaPolicy { <# .SYNOPSIS Get all user multi-factor authentication conditional access policies from Microsoft Entra ID. .DESCRIPTION Return users that are exempt from multi-factor authentication (not fully covered). .PARAMETER UserPrincipalName UserPrincipalName such as "user@domain.com" (without quotes). If not specified, all users are returned. .PARAMETER OnlyEnabled If specified, only enabled users are returned. .EXAMPLE Get-EidUserMfaPolicy; #> [cmdletbinding()] [OutputType([array])] param ( # UserPrincipalName. [Parameter(Mandatory = $false, Position = 0, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidateScript({ $_ | ForEach-Object { Test-EmailAddress -InputObject $_ } })] [string[]]$UserPrincipalName, # Only enabled users. [Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true)] [switch]$OnlyEnabled ) begin { # Write to log. $customProgress = Write-CustomProgress -Activity $MyInvocation.MyCommand.Name -CurrentOperation 'Retrieving user(s) that are exempted from MFA for conditional access policies in Microsoft Entra ID'; # Get all conditional access policies that require MFA. $conditionalAccessPolicies = Get-EidConditionalAccessMfaPolicy; # Entra properties to get. $entraUserProperties = @('Id', 'UserPrincipalName', 'DisplayName', 'AccountEnabled', 'onPremisesSyncEnabled', 'UserType', 'PasswordPolicies', 'SignInActivity', 'SignInSessionsValidFromDateTime', 'mail', 'proxyAddresses'); # If only enabled users should be returned. if ($true -eq $OnlyEnabled) { # Write to log. Write-CustomLog -Message 'Only enabled users will be returned' -Level 'Verbose'; # Get Entra (enabled) users. $entraUsers = (Get-EntraUser -Filter 'AccountEnabled eq true' -Property $entraUserProperties -All); } # Else get all users. else { # Write to log. Write-CustomLog -Message 'Both enabled and disabled users will be returned' -Level 'Verbose'; # Get all Entra users. $entraUsers = (Get-EntraUser -Property $entraUserProperties -All); } # Object array to store users. $result = @(); } process { # Foreach Entra user. foreach ($entraUser in $entraUsers) { # Protected by conditional access policy. [bool]$isProtectedByMFA = $true; # If UserPrincipalName parameter is specified and the user is not in the list. if ($PSBoundParameters.ContainsKey('UserPrincipalName') -and $entraUser.UserPrincipalName -notin $UserPrincipalName) { # Write to log. Write-CustomLog -Message ("Skipping user '{0}', because it's not in the list of specified users" -f $entraUser.UserPrincipalName) -Level 'Verbose'; # Set isProtectedByMFA to false. $isProtectedByMFA = $false; } # Object array to store policies that is targeting the user. $policiesTargetingUser = @(); # If there is no conditional access policies that require multi-factor authentication. if ($conditionalAccessPolicies.Count -eq 0) { # Write to log. Write-CustomLog -Message ("No conditional access policies require multi-factor authentication, user '{0}' is NOT protected by MFA" -f $entraUser.UserPrincipalName) -Level 'Verbose'; # Set isProtectedByMFA to false. $isProtectedByMFA = $false; } # Foreach conditional access policy that require multi-factor authentication. foreach ($conditionalAccessPolicy in $conditionalAccessPolicies) { # If the user is a guest user and the conditional access policy exclude one or more guest types. if ($entraUser.userType -eq 'Guest' -and $conditionalAccessPolicy.Users.ExcludeGuestsOrExternalUsersTypes.Count -gt 0) { # Write to log. Write-CustomLog -Message ("Guest user '{0}' is excluded from conditional access policy '{1}'" -f $entraUser.UserPrincipalName, $conditionalAccessPolicy.DisplayName) -Level 'Verbose'; # Set isProtectedByMFA to false. $isProtectedByMFA = $false; } # If the user is targeted by the conditional access policy. if ($entraUser.UserPrincipalName -in $conditionalAccessPolicy.Users.TargetedUsers) { # Write to log. Write-CustomLog -Message ("User '{0}' is targeted by conditional access policy '{1}'" -f $entraUser.UserPrincipalName, $conditionalAccessPolicy.DisplayName) -Level 'Verbose'; # Add the conditional access policy to the object array. $policiesTargetingUser += $conditionalAccessPolicy; } # Else user is not targeted by the conditional access policy. else { # Write to log. Write-CustomLog -Message ("User '{0}' is NOT targeted by conditional access policy '{1}'" -f $entraUser.UserPrincipalName, $conditionalAccessPolicy.DisplayName) -Level 'Verbose'; # Set isProtectedByMFA to false. $isProtectedByMFA = $false; } } # Create custom object to store user information. $user = [PSCustomObject]@{ Id = $entraUser.Id; UserPrincipalName = $entraUser.UserPrincipalName; DisplayName = $entraUser.DisplayName; AccountEnabled = $entraUser.AccountEnabled; DirSyncEnabled = $false; UserType = ''; PasswordPolicies = $entraUser.PasswordPolicies; LastSuccessfulSignIn = $entraUser.SignInActivity.lastSuccessfulSignInDateTime; ConditionalAccessPolicy = ($policiesTargetingUser).DisplayName; IsProtected = $false; HasMailbox = $false; }; # If the user is not a guest. if ($entraUser.userType -ne 'Guest') { # If proxyAddresses property is set. if ($false -eq [string]::IsNullOrEmpty($entraUser.proxyAddresses)) { # Boolean to track SMTP address found. [bool]$smtpAddressFound = $false; # Foreach proxy address. foreach ($proxyAddress in $entraUser.proxyAddresses) { # If SMTP address is found, break the loop. if ($true -eq $smtpAddressFound) { # If SMTP address is found, break the loop. break; } # If the proxy address starts with "SMTP:" (primary SMTP address). if ($proxyAddress -like 'SMTP:*') { # Set SMTP address found to true. $smtpAddressFound = $true; } } # If the user has a SMTP address. if ($true -eq $smtpAddressFound) { # Set Mailbox to true. $user.HasMailbox = $true; } } } # If the user is a guest. if ($entraUser.UserType -eq 'Guest') { # Set UserType to Guest. $user.UserType = 'Guest'; } # Else if the user is a member. elseif ($entraUser.UserType -eq 'Member') { # If the user principal name dont have '#EXT#@'. if ($entraUser.UserPrincipalName -notlike '*#EXT#@*') { # Set UserType to Member. $user.UserType = 'Member'; } # Else the user is external. else { # Set UserType to External. $user.UserType = 'External'; } } # If the user is synchronized from on-premises Active Directory. if ($true -eq $entraUser.onPremisesSyncEnabled) { # Set DirSyncEnabled to true. $user.DirSyncEnabled = $true; } # If the user is protected by MFA. if ($policiesTargetingUser.Count -gt 0) { # Write to log. Write-CustomLog -Message ("User '{0}' is protected by MFA" -f $entraUser.UserPrincipalName) -Level 'Verbose'; # Set IsProtected to true. $user.IsProtected = $true; } # Else user is not protected by MFA. else { # Write to log. Write-CustomLog -Message ("User '{0}' is NOT protected by MFA" -f $entraUser.UserPrincipalName) -Level 'Verbose'; } # Add the user to the object array. $result += $user; } } end { # Write to log. Write-CustomProgress @customProgress; # Return results. return $result; } } |