SHELL/5.3.5.ps1

$CheckId = "5.3.5"
$Title = "Ensure approval is required for Privileged Role Administrator activation"
$Level = "L1"
$BenchmarkType = "Automated"
$RoleDefinitionId = "e8611ab8-c189-46e8-94e1-60213ab1f814"
$RoleDisplayName = "Privileged Role Administrator"

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
}

try {
    $Filter = [uri]::EscapeDataString("scopeType eq 'DirectoryRole' and scopeId eq '/' and roleDefinitionId eq '$RoleDefinitionId'")
    $AssignmentsUri = "https://graph.microsoft.com/beta/policies/roleManagementPolicyAssignments?`$filter=$Filter"
    $AssignmentsResponse = Invoke-MgGraphRequest -Uri $AssignmentsUri -Method GET -ErrorAction Stop
    $Assignments = @(Get-PropValue -Object $AssignmentsResponse -Name "value")

    if ($Assignments.Count -eq 0) {
        [pscustomobject]@{
            CheckId = $CheckId
            Title = $Title
            Level = $Level
            BenchmarkType = $BenchmarkType
            Status = "FAIL"
            Pass = $false
            Evidence = [pscustomobject]@{
                RoleDefinitionId = $RoleDefinitionId
                RoleDisplayName = $RoleDisplayName
                RoleManagementPolicyAssignmentCount = 0
                SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
            }
            Error = "No role management policy assignment was found for Privileged Role Administrator."
            Timestamp = Get-Date
        }
        return
    }

    $Assignment = $Assignments | Select-Object -First 1
    $PolicyId = [string](Get-PropValue -Object $Assignment -Name "policyId")
    if ([string]::IsNullOrWhiteSpace($PolicyId)) {
        throw "Role management policy assignment does not include a policyId."
    }

    $RulesUri = "https://graph.microsoft.com/beta/policies/roleManagementPolicies/$PolicyId/rules"
    $RulesResponse = Invoke-MgGraphRequest -Uri $RulesUri -Method GET -ErrorAction Stop
    $Rules = @(Get-PropValue -Object $RulesResponse -Name "value")

    $ApprovalRules = @($Rules | Where-Object {
            ([string](Get-PropValue -Object $_ -Name "@odata.type")) -match '(?i)approval' -and
            (([string](Get-PropValue -Object (Get-PropValue -Object $_ -Name "target") -Name "caller")) -match '^(?i:enduser)$')
        })

    $RuleEvaluations = foreach ($Rule in $ApprovalRules) {
        $Target = Get-PropValue -Object $Rule -Name "target"
        $Setting = Get-PropValue -Object $Rule -Name "setting"
        $Stages = @(Get-PropValue -Object $Setting -Name "approvalStages")
        $PrimaryApprovers = @()
        foreach ($Stage in $Stages) {
            $PrimaryApprovers += @(Get-PropValue -Object $Stage -Name "primaryApprovers")
        }

        $ApproverCount = @($PrimaryApprovers | Where-Object { $_ }).Count
        $IsApprovalRequired = [bool](Get-PropValue -Object $Setting -Name "isApprovalRequired")
        $Operations = @(Get-PropValue -Object $Target -Name "operations")

        [pscustomobject]@{
            RuleId = [string](Get-PropValue -Object $Rule -Name "id")
            Caller = [string](Get-PropValue -Object $Target -Name "caller")
            Operations = $Operations
            IsApprovalRequired = $IsApprovalRequired
            ApproverCount = $ApproverCount
            IsCompliant = $IsApprovalRequired -and ($ApproverCount -ge 2)
        }
    }

    $CompliantRules = @($RuleEvaluations | Where-Object { $_.IsCompliant })
    $Pass = $CompliantRules.Count -gt 0
    $Status = if ($Pass) { "PASS" } else { "FAIL" }

    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = $Status
        Pass = $Pass
        Evidence = [pscustomobject]@{
            RoleDefinitionId = $RoleDefinitionId
            RoleDisplayName = $RoleDisplayName
            PolicyId = $PolicyId
            RoleManagementPolicyAssignmentCount = $Assignments.Count
            ApprovalRuleCount = $ApprovalRules.Count
            RuleEvaluations = @($RuleEvaluations)
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = if ($Pass) { $null } else { "No Privileged Role Administrator activation approval rule was found with approval required and at least two approvers." }
        Timestamp = Get-Date
    }
}
catch {
    [pscustomobject]@{
        CheckId = $CheckId
        Title = $Title
        Level = $Level
        BenchmarkType = $BenchmarkType
        Status = "ERROR"
        Pass = $null
        Evidence = [pscustomobject]@{
            RoleDefinitionId = $RoleDefinitionId
            RoleDisplayName = $RoleDisplayName
            SourceDocument = "CIS_Microsoft_365_Foundations_Benchmark_v6.0.1"
        }
        Error = $_.Exception.Message
        Timestamp = Get-Date
    }
}