SHELL/5.1.8.1.ps1

$CheckId = "5.1.8.1"
$Title = "Ensure that password hash sync is enabled for hybrid deployments"
$Level = "L1"
$BenchmarkType = "Manual"
$AuditCommands = @(
    "Get-MgOrganization",
    "Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/directory/onPremisesSynchronization'"
)

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

    if ($null -eq $Object) { return $null }
    if ($Object -is [System.Collections.IDictionary]) {
        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
}

try {
    $Org = Get-MgOrganization -ErrorAction Stop | Select-Object -First 1
    if (-not $Org) {
        throw "No organization object returned."
    }

    $IsHybrid = [bool]$Org.OnPremisesSyncEnabled
    if (-not $IsHybrid) {
        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = "PASS"
            Pass = $true
            Evidence = [pscustomobject]@{
                AuditCommands = $AuditCommands
                OnPremisesSyncEnabled = $false
                Applicability = "NotApplicableToCloudOnlyTenant"
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = $null
            Timestamp = Get-Date
        }
        return
    }

    try {
        $SyncConfig = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/directory/onPremisesSynchronization" -ErrorAction Stop
        $SyncItems = @($SyncConfig.value)
        $PhsEnabled = $false

        foreach ($Item in $SyncItems) {
            $Features = Get-PropValue -Object $Item -Name "features"
            if ($Features -and (Get-PropValue -Object $Features -Name "passwordHashSyncEnabled") -eq $true) {
                $PhsEnabled = $true
                break
            }
        }

        $Pass = $PhsEnabled
        $Status = if ($Pass) { "PASS" } else { "FAIL" }

        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = $Status
            Pass = $Pass
            Evidence = [pscustomobject]@{
                AuditCommands = $AuditCommands
                OnPremisesSyncEnabled = $true
                SyncItemCount = @($SyncItems).Count
                PasswordHashSyncEnabled = $PhsEnabled
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = if ($Pass) { $null } else { "Hybrid deployment detected but password hash sync is not enabled." }
            Timestamp = Get-Date
        }
    }
    catch {
        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = "MANUAL_REVIEW"
            Pass = $null
            Evidence = [pscustomobject]@{
                AuditCommands = $AuditCommands
                OnPremisesSyncEnabled = $true
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = "Hybrid deployment detected but password hash sync could not be verified automatically: $($_.Exception.Message)"
            Timestamp = Get-Date
        }
    }
}
catch {
    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = "MANUAL_REVIEW"
        Pass = $null
        Evidence = [pscustomobject]@{
            AuditCommands = $AuditCommands
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = "Unable to determine deployment type automatically: $($_.Exception.Message)"
        Timestamp = Get-Date
    }
}