Enhance user MFA method reporting by clarifying sign-in preference handling and adding module dependency checks
This commit is contained in:
@@ -257,17 +257,24 @@ function Get-UserAuthMethodDetail {
|
||||
if ($friendly.Category -eq 'Phone') { $hasPhoneMethod = $true }
|
||||
}
|
||||
|
||||
# Best-effort default/preferred method. This endpoint reflects the user's
|
||||
# own sign-in preference and, unlike the tenant-wide usage/insights report,
|
||||
# is not gated behind a P1/P2 license - but treat failures as "unknown"
|
||||
# rather than fatal, since behavior can vary by tenant/SDK version.
|
||||
# Best-effort default/preferred method. This endpoint only reflects an
|
||||
# explicit override the user (or an admin) has set - unlike the
|
||||
# tenant-wide usage/insights report, it's not gated behind a P1/P2
|
||||
# license - but treat failures as "unknown" rather than fatal, since
|
||||
# behavior can vary by tenant/SDK version. Deliberately NOT guessed/
|
||||
# inferred when unavailable: Entra ID's actual method selection (e.g.
|
||||
# under System-preferred MFA) depends on per-user state this API doesn't
|
||||
# expose, so a guess here can be flatly wrong and is worse than admitting
|
||||
# it's unknown - this value drives real remediation decisions.
|
||||
$defaultMethod = $null
|
||||
try {
|
||||
$preference = Get-MgBetaUserAuthenticationSignInPreference -UserId $UserId -ErrorAction Stop
|
||||
$defaultMethod = $preference.UserPreferredMethodForSecondaryAuthentication
|
||||
if ($preference.UserPreferredMethodForSecondaryAuthentication -and $preference.UserPreferredMethodForSecondaryAuthentication -ne 'none') {
|
||||
$defaultMethod = $preference.UserPreferredMethodForSecondaryAuthentication
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Verbose "No sign-in preference available for user '$UserId' (falling back to heuristic): $_"
|
||||
Write-Warning "No sign-in preference available for user '$UserId': $_"
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
@@ -403,6 +410,25 @@ $($methodRows -join "`n")
|
||||
|
||||
# --- Main --------------------------------------------------------------
|
||||
try {
|
||||
# Fail fast and loudly if a module this script depends on isn't
|
||||
# installed OR can't actually be loaded (e.g. an assembly-version
|
||||
# conflict with another installed Microsoft.Graph module version),
|
||||
# rather than letting every per-user call into it fail silently later
|
||||
# and produce an incomplete/misleading report. Microsoft.Graph.Beta.
|
||||
# Identity.SignIns provides Get-MgBetaUserAuthenticationSignInPreference,
|
||||
# which reads each user's actual default sign-in method - there is no
|
||||
# v1.0/GA equivalent, this data is beta-only in Microsoft Graph.
|
||||
$requiredBetaModule = 'Microsoft.Graph.Beta.Identity.SignIns'
|
||||
if (-not (Get-Module -ListAvailable -Name $requiredBetaModule)) {
|
||||
throw "Required module '$requiredBetaModule' is not installed. It's needed to read each user's actual default sign-in method. Install it with: Install-Module $requiredBetaModule -Scope CurrentUser"
|
||||
}
|
||||
try {
|
||||
Import-Module -Name $requiredBetaModule -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
throw "Required module '$requiredBetaModule' is installed but failed to load - this is usually caused by multiple mismatched Microsoft.Graph module versions installed side by side (an assembly-version conflict), not a missing module. Run: Get-Module -ListAvailable 'Microsoft.Graph*' | Group-Object Name | Where-Object { (`$_.Group.Version | Sort-Object -Unique).Count -gt 1 } to find the mismatched ones, update them all to the same version, and remove the old ones. Underlying error: $_"
|
||||
}
|
||||
|
||||
Write-Verbose 'Connecting to Microsoft Graph...'
|
||||
$requiredScopes = @(
|
||||
'User.Read.All'
|
||||
@@ -473,7 +499,13 @@ try {
|
||||
$_ -notin @('mobilePhone', 'alternateMobilePhone', 'officePhone', 'email', 'password')
|
||||
}
|
||||
$hasStrongMethod = [bool]$strongRegistered
|
||||
# This report field is also "none" (a literal string, not $null)
|
||||
# for users without an explicit override - most commonly because
|
||||
# the tenant runs System-preferred MFA. Normalize it so the
|
||||
# fallback heuristic below actually kicks in instead of the row
|
||||
# showing the literal word "none" as if it were a real method.
|
||||
$defaultMethod = $regDetail.UserPreferredMethodForSecondaryAuthentication
|
||||
if ($defaultMethod -eq 'none') { $defaultMethod = $null }
|
||||
}
|
||||
else {
|
||||
# Fallback path: per-user methods API, works without P1/P2.
|
||||
|
||||
Reference in New Issue
Block a user