SHELL/5.2.3.1.ps1

$CheckId = "5.2.3.1"
$Title = "Ensure Microsoft Authenticator is configured to protect against MFA fatigue"
$Level = "L1"
$BenchmarkType = "Automated"

function Get-PropValue {
    param(
        [AllowNull()]$Object,
        [string]$Name
    )

    if ($null -eq $Object) {
        return $null
    }

    if ($Object -is [hashtable]) {
        foreach ($Key in $Object.Keys) {
            if ([string]$Key -ieq $Name) {
                return $Object[$Key]
            }
        }
    }

    if ($Object.PSObject -and $Object.PSObject.Properties) {
        foreach ($Property in $Object.PSObject.Properties) {
            if ([string]$Property.Name -ieq $Name) {
                return $Property.Value
            }
        }
    }

    return $null
}

function Get-NestedValue {
    param(
        [AllowNull()]$Object,
        [string[]]$Path
    )

    $Current = $Object
    foreach ($Segment in $Path) {
        if ($null -eq $Current) {
            return $null
        }

        $Current = Get-PropValue -Object $Current -Name $Segment
    }

    return $Current
}

function Get-ConfigState {
    param([AllowNull()]$Config)

    $State = Get-PropValue -Object $Config -Name "state"
    if ($null -eq $State) {
        $State = Get-PropValue -Object (Get-PropValue -Object $Config -Name "AdditionalProperties") -Name "state"
    }

    return [string]$State
}

function Get-FeatureState {
    param(
        [AllowNull()]$FeatureSettings,
        [string]$FeatureName
    )

    $FeatureNode = Get-PropValue -Object $FeatureSettings -Name $FeatureName
    if ($null -eq $FeatureNode) {
        $FeatureNode = Get-PropValue -Object (Get-PropValue -Object $FeatureSettings -Name "AdditionalProperties") -Name $FeatureName
    }

    $State = Get-PropValue -Object $FeatureNode -Name "state"
    if ($null -eq $State) {
        $State = Get-PropValue -Object (Get-PropValue -Object $FeatureNode -Name "AdditionalProperties") -Name "state"
    }

    return [string]$State
}

try {
    $Policy = Get-MgPolicyAuthenticationMethodPolicy -ErrorAction Stop
    $Configurations = @($Policy.AuthenticationMethodConfigurations)

    $AuthenticatorConfig = @($Configurations | Where-Object { ([string]$_.Id) -ieq "MicrosoftAuthenticator" } | Select-Object -First 1)
    if ($AuthenticatorConfig.Count -eq 0) {
        throw "Microsoft Authenticator configuration was not returned by Get-MgPolicyAuthenticationMethodPolicy."
    }

    $Config = $AuthenticatorConfig[0]
    $ConfigState = Get-ConfigState -Config $Config
    $IsEnabled = ($ConfigState -match '^(?i:enabled)$')

    $IncludeTargets = @(Get-PropValue -Object $Config -Name "includeTargets")
    if ($IncludeTargets.Count -eq 0) {
        $IncludeTargets = @(Get-PropValue -Object (Get-PropValue -Object $Config -Name "AdditionalProperties") -Name "includeTargets")
    }

    $TargetsAllUsers = @($IncludeTargets | Where-Object {
            $TargetId = [string](Get-PropValue -Object $_ -Name "id")
            $TargetType = [string](Get-PropValue -Object $_ -Name "targetType")
            ($TargetId -ieq "all_users") -or ($TargetType -ieq "allUsers")
        })

    $FeatureSettings = Get-PropValue -Object $Config -Name "featureSettings"
    if ($null -eq $FeatureSettings) {
        $FeatureSettings = Get-PropValue -Object (Get-PropValue -Object $Config -Name "AdditionalProperties") -Name "featureSettings"
    }

    $NumberMatchingState = Get-FeatureState -FeatureSettings $FeatureSettings -FeatureName "numberMatchingRequiredState"
    $DisplayAppInfoState = Get-FeatureState -FeatureSettings $FeatureSettings -FeatureName "displayAppInformationRequiredState"
    $DisplayLocationState = Get-FeatureState -FeatureSettings $FeatureSettings -FeatureName "displayLocationInformationRequiredState"

    $NumberMatchingEnabled = ($NumberMatchingState -match '^(?i:enabled)$')
    $DisplayAppInfoEnabled = ($DisplayAppInfoState -match '^(?i:enabled)$')
    $DisplayLocationEnabled = ($DisplayLocationState -match '^(?i:enabled)$')

    $Pass = $IsEnabled -and ($TargetsAllUsers.Count -gt 0) -and $NumberMatchingEnabled -and $DisplayAppInfoEnabled -and $DisplayLocationEnabled
    $Status = if ($Pass) { "PASS" } else { "FAIL" }

    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = $Status
        Pass = $Pass
        Evidence = [pscustomobject]@{
            ConfigId = [string]$Config.Id
            ConfigState = $ConfigState
            IncludeTargets = @($IncludeTargets)
            TargetsAllUsers = ($TargetsAllUsers.Count -gt 0)
            NumberMatchingState = $NumberMatchingState
            DisplayAppInformationState = $DisplayAppInfoState
            DisplayLocationInformationState = $DisplayLocationState
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = if ($Pass) { $null } else { "Microsoft Authenticator must be enabled for all users with number matching, app information, and location information protections enabled." }
        Timestamp = Get-Date
    }
}
catch {
    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = "ERROR"
        Pass = $null
        Evidence = [pscustomobject]@{
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = $_.Exception.Message
        Timestamp = Get-Date
    }
}