Public/Copy-NLBaselineCAPolicies.ps1

function Copy-NLBaselineCAPolicies {
    <#
    .SYNOPSIS
    Copy Conditional Access policies for pilot testing
     
    .DESCRIPTION
    Creates copies of existing Conditional Access policies with a new prefix for pilot testing.
    Useful for testing policy changes without affecting production policies.
     
    .EXAMPLE
    Copy-NLBaselineCAPolicies -SourcePrefix "CA200" -DestinationPrefix "PILOT-CA200"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$SourcePrefix,
        
        [Parameter(Mandatory = $true)]
        [string]$DestinationPrefix,
        
        [Parameter(Mandatory = $false)]
        [ValidateSet("enabled", "enabledForReportingButNotEnforced", "disabled")]
        [string]$NewState = "enabledForReportingButNotEnforced"
    )
    
    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 " COPY POLICIES FOR PILOT" -ForegroundColor Cyan
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "Source prefix: $SourcePrefix" -ForegroundColor Yellow
        Write-Host "Destination prefix: $DestinationPrefix" -ForegroundColor Yellow
        Write-Host "New state: $NewState" -ForegroundColor Yellow
        Write-Host ""
        
        # Get policies matching source prefix
        Write-Host "Retrieving policies with prefix '$SourcePrefix'..." -ForegroundColor Gray
        $policies = Get-AllConditionalAccessPolicies
        
        $sourcePolicies = $policies | Where-Object { $_.DisplayName -like "$SourcePrefix*" }
        
        if ($sourcePolicies.Count -eq 0) {
            Write-Error "No policies found with prefix '$SourcePrefix'"
            return
        }
        
        Write-Host "Found $($sourcePolicies.Count) policies to copy" -ForegroundColor Green
        Write-Host ""
        
        $copiedCount = 0
        $errors = @()
        
        foreach ($policy in $sourcePolicies) {
            try {
                Write-Host "Copying: $($policy.displayName)" -ForegroundColor Yellow
                
                # Create new policy object
                $newPolicy = @{}
                
                # Copy all properties except read-only ones
                $policy.PSObject.Properties | ForEach-Object {
                    $propName = $_.Name
                    if ($propName -notmatch '^@odata\.' -and 
                        $propName -ne 'id' -and 
                        $propName -ne 'createdDateTime' -and 
                        $propName -ne 'modifiedDateTime' -and 
                        $propName -ne 'deletedDateTime' -and
                        $propName -ne 'templateId') {
                        $newPolicy[$propName] = $_.Value
                    }
                }
                
                # Update display name with new prefix
                $newPolicy.displayName = $policy.displayName -replace "^$([regex]::Escape($SourcePrefix))", $DestinationPrefix
                
                # Set new state
                $newPolicy.state = $NewState
                
                # Create policy using REST API
                $body = $newPolicy | ConvertTo-Json -Depth 20
                
                $invokeCmd = Get-Command Invoke-MgGraphRequest -ErrorAction SilentlyContinue
                if ($invokeCmd) {
                    $newPolicyResult = Invoke-MgGraphRequest -Method POST `
                        -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
                        -Body $body `
                        -ContentType "application/json" `
                        -ErrorAction Stop
                    
                    Write-Host " Created: $($newPolicy.displayName)" -ForegroundColor Green
                    $copiedCount++
                }
                else {
                    throw "Invoke-MgGraphRequest not available"
                }
            }
            catch {
                $errors += "Error copying $($policy.displayName): $_"
                Write-Host " Error: $_" -ForegroundColor Red
            }
        }
        
        Write-Host ""
        Write-Host "========================================" -ForegroundColor Green
        Write-Host " SUMMARY" -ForegroundColor Green
        Write-Host "========================================" -ForegroundColor Green
        Write-Host "Copied: $copiedCount 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 copying policies: $_"
    }
}