SHELL/4.2.ps1

$CheckId = "4.2"
$Title = "Ensure device enrollment for personally owned devices is blocked by default"
$Level = "L2"
$BenchmarkType = "Automated"
$AuditCommands = @(
    '$Uri = "https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations"',
    '$Config = (Invoke-MgGraphRequest -Uri $Uri -Method GET).value | Where-Object { $_.id -match "DefaultPlatformRestrictions" -and $_.priority -eq 0 }'
)

function Get-NestedValue {
    param(
        [Parameter(Mandatory = $true)][AllowNull()][object]$InputObject,
        [Parameter(Mandatory = $true)][string[]]$Path
    )

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

        if ($Current -is [System.Collections.IDictionary]) {
            if ($Current.Contains($Segment)) {
                $Current = $Current[$Segment]
            }
            else {
                return $null
            }
        }
        else {
            $Prop = $Current.PSObject.Properties[$Segment]
            if ($null -eq $Prop) {
                return $null
            }
            $Current = $Prop.Value
        }
    }

    return $Current
}

try {
    if (-not (Get-Command -Name Invoke-MgGraphRequest -ErrorAction SilentlyContinue)) {
        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = "ERROR"
            Pass = $null
            Evidence = [pscustomobject]@{
                AuditCommands = $AuditCommands
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = "Invoke-MgGraphRequest cmdlet is unavailable in the current session."
            Timestamp = Get-Date
        }
        return
    }

    $Uri = 'https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations'
    $AllConfigs = @((Invoke-MgGraphRequest -Uri $Uri -Method GET -ErrorAction Stop).value)
    $Config = @($AllConfigs | Where-Object {
        ([string]$_.id -match 'DefaultPlatformRestrictions') -and ([int]$_.priority -eq 0)
    } | Select-Object -First 1)

    if (@($Config).Count -eq 0) {
        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = "ERROR"
            Pass = $null
            Evidence = [pscustomobject]@{
                AuditCommands = $AuditCommands
                Uri = $Uri
                ConfigCount = @($AllConfigs).Count
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = "DefaultPlatformRestrictions (priority 0) configuration was not found."
            Timestamp = Get-Date
        }
        return
    }

    $TargetConfig = $Config[0]

    $PlatformMap = [ordered]@{
        Windows = "windowsRestriction"
        iOS = "iosRestriction"
        AndroidForWork = "androidForWorkRestriction"
        macOS = "macOSRestriction"
        Android = "androidRestriction"
    }

    $Report = @()
    $FailureReasons = [System.Collections.Generic.List[string]]::new()
    $ManualReasons = [System.Collections.Generic.List[string]]::new()

    foreach ($Platform in $PlatformMap.Keys) {
        $RestrictionPath = $PlatformMap[$Platform]
        $PersonalBlockedRaw = Get-NestedValue -InputObject $TargetConfig -Path @($RestrictionPath, "personalDeviceEnrollmentBlocked")
        $PlatformBlockedRaw = Get-NestedValue -InputObject $TargetConfig -Path @($RestrictionPath, "platformBlocked")

        $PersonalBlocked = if ($null -eq $PersonalBlockedRaw) { $null } else { [bool]$PersonalBlockedRaw }
        $PlatformBlocked = if ($null -eq $PlatformBlockedRaw) { $null } else { [bool]$PlatformBlockedRaw }

        $Compliant = $null
        if ($null -ne $PersonalBlocked -or $null -ne $PlatformBlocked) {
            $Compliant = (($PersonalBlocked -eq $true) -or ($PlatformBlocked -eq $true))
        }

        $Report += [pscustomobject]@{
            Platform = $Platform
            PersonalDeviceEnrollmentBlocked = $PersonalBlocked
            PlatformBlocked = $PlatformBlocked
            Compliant = $Compliant
            ComplianceRule = "personalDeviceEnrollmentBlocked = True OR platformBlocked = True"
        }

        if ($null -eq $Compliant) {
            $ManualReasons.Add("Could not determine enrollment restriction values for $Platform.")
        }
        elseif (-not $Compliant) {
            $FailureReasons.Add("$Platform is not compliant (personal devices are not blocked and platform is not fully blocked).")
        }
    }

    $Status = "PASS"
    $Pass = $true
    $ErrorMessage = $null

    if ($FailureReasons.Count -gt 0) {
        $Status = "FAIL"
        $Pass = $false
        $ErrorMessage = ($FailureReasons -join " ")
    }
    elseif ($ManualReasons.Count -gt 0) {
        $Status = "FAIL"
        $Pass = $false
        $ErrorMessage = "One or more platform restrictions are incomplete or missing values: $($ManualReasons -join " ")"
    }

    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = $Status
        Pass = $Pass
        Evidence = [pscustomobject]@{
            AuditCommands = $AuditCommands
            Uri = $Uri
            ConfigId = [string]$TargetConfig.id
            ConfigPriority = $TargetConfig.priority
            PlatformReport = @($Report)
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = $ErrorMessage
        Timestamp = Get-Date
    }
}
catch {
    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = "ERROR"
        Pass = $null
        Evidence = [pscustomobject]@{
            AuditCommands = $AuditCommands
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = $_.Exception.Message
        Timestamp = Get-Date
    }
}