Public/Set-NLBaselineCAPolicyAdminRoles.ps1

function Set-NLBaselineCAPolicyAdminRoles {
    <#
    .SYNOPSIS
    Add or remove admin roles from Conditional Access policies
     
    .DESCRIPTION
    Allows bulk management of admin role inclusions/exclusions in Conditional Access policies.
    Useful for ensuring admin roles are properly protected.
     
    .EXAMPLE
    Set-NLBaselineCAPolicyAdminRoles -Action Include -RoleIds @("role-id-1", "role-id-2") -PolicyPrefix "CA100"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet("Include", "Exclude")]
        [string]$Action,
        
        [Parameter(Mandatory = $true)]
        [string[]]$RoleIds,
        
        [Parameter(Mandatory = $false)]
        [string]$PolicyPrefix = ""
    )
    
    try {
        # Check connection
        $context = Get-MgContext -ErrorAction SilentlyContinue
        if (-not $context -or -not $context.TenantId) {
            Write-Host "Not connected to Microsoft 365. Connecting..." -ForegroundColor Yellow
            Write-Host ""
            $connection = Connect-NLBaselineCA
            if (-not $connection) {
                Write-Error "Cannot connect to Microsoft 365"
                return
            }
            $context = Get-MgContext
        }
        
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host " ADMIN ROLES MANAGEMENT" -ForegroundColor Cyan
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "Action: $Action admin roles" -ForegroundColor Yellow
        Write-Host "Roles: $($RoleIds.Count)" -ForegroundColor Yellow
        if ($PolicyPrefix) {
            Write-Host "Filter: Policies starting with '$PolicyPrefix'" -ForegroundColor Yellow
        }
        Write-Host ""
        
        # Get all policies
        Write-Host "Retrieving Conditional Access policies..." -ForegroundColor Gray
        $policies = Get-AllConditionalAccessPolicies
        
        # Filter by prefix if specified
        if ($PolicyPrefix) {
            $policies = $policies | Where-Object { $_.DisplayName -like "$PolicyPrefix*" }
        }
        
        Write-Host "Found $($policies.Count) policies to process" -ForegroundColor Green
        Write-Host ""
        
        $updatedCount = 0
        $errors = @()
        
        foreach ($policy in $policies) {
            try {
                $needsUpdate = $false
                $policyUpdate = @{}
                
                # Ensure conditions structure exists
                if (-not $policy.conditions) {
                    $policyUpdate.conditions = @{
                        "@odata.type" = "#microsoft.graph.conditionalAccessConditionSet"
                        users = @{
                            "@odata.type" = "#microsoft.graph.conditionalAccessUsers"
                            includeUsers = if ($policy.conditions.users.includeUsers) { $policy.conditions.users.includeUsers } else { @("All") }
                            excludeUsers = if ($policy.conditions.users.excludeUsers) { $policy.conditions.users.excludeUsers } else { @() }
                            excludeGroups = if ($policy.conditions.users.excludeGroups) { $policy.conditions.users.excludeGroups } else { @() }
                        }
                    }
                    $needsUpdate = $true
                }
                else {
                    $policyUpdate.conditions = $policy.conditions
                }
                
                # Ensure users structure exists
                if (-not $policyUpdate.conditions.users) {
                    $policyUpdate.conditions.users = @{
                        "@odata.type" = "#microsoft.graph.conditionalAccessUsers"
                        includeUsers = @("All")
                        excludeUsers = @()
                        excludeGroups = @()
                    }
                    $needsUpdate = $true
                }
                
                # Initialize role arrays if needed
                if ($Action -eq "Include") {
                    if (-not $policyUpdate.conditions.users.includeRoles) {
                        $policyUpdate.conditions.users.includeRoles = @()
                        $needsUpdate = $true
                    }
                    
                    # Add roles that aren't already included
                    $currentRoles = if ($policyUpdate.conditions.users.includeRoles) { $policyUpdate.conditions.users.includeRoles } else { @() }
                    $newRoles = $RoleIds | Where-Object { $_ -notin $currentRoles }
                    if ($newRoles.Count -gt 0) {
                        $policyUpdate.conditions.users.includeRoles = $currentRoles + $newRoles
                        $needsUpdate = $true
                        Write-Host " Adding roles to: $($policy.displayName)" -ForegroundColor Gray
                    }
                }
                elseif ($Action -eq "Exclude") {
                    if (-not $policyUpdate.conditions.users.excludeRoles) {
                        $policyUpdate.conditions.users.excludeRoles = @()
                        $needsUpdate = $true
                    }
                    
                    # Add roles that aren't already excluded
                    $currentRoles = if ($policyUpdate.conditions.users.excludeRoles) { $policyUpdate.conditions.users.excludeRoles } else { @() }
                    $newRoles = $RoleIds | Where-Object { $_ -notin $currentRoles }
                    if ($newRoles.Count -gt 0) {
                        $policyUpdate.conditions.users.excludeRoles = $currentRoles + $newRoles
                        $needsUpdate = $true
                        Write-Host " Excluding roles from: $($policy.displayName)" -ForegroundColor Gray
                    }
                }
                
                if ($needsUpdate) {
                    # Update policy using REST API
                    $body = @{
                        conditions = $policyUpdate.conditions
                    } | ConvertTo-Json -Depth 10
                    
                    $invokeCmd = Get-Command Invoke-MgGraphRequest -ErrorAction SilentlyContinue
                    if ($invokeCmd) {
                        Invoke-MgGraphRequest -Method PATCH `
                            -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/$($policy.Id)" `
                            -Body $body `
                            -ContentType "application/json" `
                            -ErrorAction Stop
                        
                        $updatedCount++
                    }
                    else {
                        throw "Invoke-MgGraphRequest not available"
                    }
                }
            }
            catch {
                $errors += "Error updating $($policy.displayName): $_"
                Write-Host " Error: $_" -ForegroundColor Red
            }
        }
        
        Write-Host ""
        Write-Host "========================================" -ForegroundColor Green
        Write-Host " SUMMARY" -ForegroundColor Green
        Write-Host "========================================" -ForegroundColor Green
        Write-Host "Updated: $updatedCount policies" -ForegroundColor White
        if ($errors.Count -gt 0) {
            Write-Host "Errors: $($errors.Count)" -ForegroundColor Red
            foreach ($error in $errors) {
                Write-Host " - $error" -ForegroundColor Yellow
            }
        }
        Write-Host ""
    }
    catch {
        Write-Error "Error managing admin roles: $_"
    }
}