Public/Deploy-NLBaselineWithRings.ps1

<#
.SYNOPSIS
    Deploys NLBaseline policies with ring-based assignments
.DESCRIPTION
    Deploys all NLBaseline policies and assigns them to groups based on ring configuration (Ring0, Ring1, Ring2)
    Ring configuration is stored in Workspace\Deployment\ring-configuration.json
.PARAMETER Ring
    Ring to deploy: Ring0, Ring1, Ring2, or All
.PARAMETER DryRun
    Validate and show what would be deployed without actually deploying
.EXAMPLE
    Deploy-NLBaselineWithRings -Ring "Ring0"
    Deploy-NLBaselineWithRings -Ring "All" -DryRun
#>

function Deploy-NLBaselineWithRings {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet("Ring0", "Ring1", "Ring2", "All")]
        [string]$Ring,
        
        [switch]$DryRun
    )

    $ErrorActionPreference = "Stop"
    $workspacePath = Get-WorkspacePath
    if (-not $workspacePath) {
        Write-Error "Workspace not configured. Run Initialize-NLBaseline first."
        return
    }

    $config = Get-Config -WorkspacePath $workspacePath
    if (-not $config -or [string]::IsNullOrEmpty($config.AppRegistration.ClientId) -or [string]::IsNullOrEmpty($config.AppRegistration.ClientSecret) -or [string]::IsNullOrEmpty($config.AppRegistration.TenantId)) {
        Write-Error "App Registration not configured in config.json."
        return
    }

    # Load ring configuration
    $deploymentPath = Join-Path -Path $workspacePath -ChildPath "Deployment"
    $ringConfigPath = Join-Path -Path $deploymentPath -ChildPath "ring-configuration.json"
    
    if (-not (Test-Path -Path $ringConfigPath)) {
        Write-Error "Ring configuration not found at: $ringConfigPath. Create it first using Deployment Management menu."
        return
    }

    try {
        $ringConfig = Get-Content -Path $ringConfigPath -Raw | ConvertFrom-Json
    }
    catch {
        Write-Error "Failed to parse ring configuration: $_"
        return
    }

    Write-Host "`nDeploying NLBaseline with Ring Configuration`n" -ForegroundColor Cyan
    Write-Host "Ring: $Ring" -ForegroundColor White
    if ($DryRun) {
        Write-Host "[DRY RUN MODE - No changes will be made]" -ForegroundColor Yellow
    }

    if (-not $DryRun) {
        $connected = Connect-Intune -Config $config
        if (-not $connected) {
            Write-Error "Failed to connect to Microsoft Graph."
            return
        }
    }

    # Determine which rings to deploy
    $ringsToDeploy = @()
    if ($Ring -eq "All") {
        $ringsToDeploy = @("Ring0", "Ring1", "Ring2")
    }
    else {
        $ringsToDeploy = @($Ring)
    }

    foreach ($ringName in $ringsToDeploy) {
        Write-Host "`n=== Processing $ringName ===" -ForegroundColor Cyan
        
        if (-not $ringConfig.$ringName) {
            Write-Warning "Ring configuration for $ringName not found. Skipping..."
            continue
        }

        $ringData = $ringConfig.$ringName
        
        # Get assignments (groups or AllDevices)
        $assignments = @()
        if ($ringData.Assignments) {
            foreach ($assignment in $ringData.Assignments) {
                if ($assignment -eq "AllDevices") {
                    $assignments += @{
                        Type = "AllDevices"
                        Target = "AllDevices"
                    }
                }
                else {
                    # Assume it's a group GUID
                    $assignments += @{
                        Type = "Group"
                        Target = $assignment
                    }
                }
            }
        }

        if ($assignments.Count -eq 0) {
            Write-Warning "No assignments configured for $ringName. Skipping..."
            continue
        }

        Write-Host "Assignments: $($assignments.Count)" -ForegroundColor White
        foreach ($assignment in $assignments) {
            Write-Host " - $($assignment.Type): $($assignment.Target)" -ForegroundColor Gray
        }

        # Deploy all baseline components
        Write-Host "`nDeploying baseline components..." -ForegroundColor Yellow
        try {
            if ($DryRun) {
                Write-Host "[DRY RUN] Would deploy all baseline components" -ForegroundColor Cyan
            }
            else {
                Deploy-AllNLBaselineToIntune -IncludeBaseline -IncludeCIS -IncludeEndpointSecurity -IncludeCompliance -IncludeOther
            }
        }
        catch {
            Write-Warning "Error deploying baseline components: $_"
        }

        # Get all NLBaseline policies and assign them
        Write-Host "`nAssigning policies to groups..." -ForegroundColor Yellow
        
        if (-not $DryRun) {
            try {
                # Get all device configuration policies with NLBaseline prefix
                try {
                    $policiesResponse = Invoke-IntuneGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations"
                    $policies = $policiesResponse.value | Where-Object { $_.displayName -like "NLBaseline - *" }
                    
                    # Handle pagination
                    while ($policiesResponse.'@odata.nextLink') {
                        $policiesResponse = Invoke-IntuneGraphRequest -Method GET -Uri $policiesResponse.'@odata.nextLink'
                        $policies += $policiesResponse.value | Where-Object { $_.displayName -like "NLBaseline - *" }
                    }
                }
                catch {
                    Write-Warning "Could not retrieve device configuration policies: $_"
                    $policies = @()
                }

                # Get compliance policies with NLBaseline prefix
                try {
                    $complianceResponse = Invoke-IntuneGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceCompliancePolicies"
                    $compliancePolicies = $complianceResponse.value | Where-Object { $_.displayName -like "NLBaseline - *" }
                    
                    # Handle pagination
                    while ($complianceResponse.'@odata.nextLink') {
                        $complianceResponse = Invoke-IntuneGraphRequest -Method GET -Uri $complianceResponse.'@odata.nextLink'
                        $compliancePolicies += $complianceResponse.value | Where-Object { $_.displayName -like "NLBaseline - *" }
                    }
                }
                catch {
                    Write-Warning "Could not retrieve compliance policies: $_"
                    $compliancePolicies = @()
                }

                $totalPolicies = ($policies | Measure-Object).Count + ($compliancePolicies | Measure-Object).Count
                Write-Host "Found $totalPolicies NLBaseline policies" -ForegroundColor Green

                # Assign device configuration policies
                foreach ($policy in $policies) {
                    foreach ($assignment in $assignments) {
                        try {
                            Assign-IntunePolicyToGroup -PolicyId $policy.id -PolicyType "DeviceConfiguration" -Assignment $assignment -DryRun:$DryRun
                        }
                        catch {
                            Write-Warning "Failed to assign policy $($policy.displayName): $_"
                        }
                    }
                }

                # Assign compliance policies
                foreach ($policy in $compliancePolicies) {
                    foreach ($assignment in $assignments) {
                        try {
                            Assign-IntunePolicyToGroup -PolicyId $policy.id -PolicyType "DeviceCompliance" -Assignment $assignment -DryRun:$DryRun
                        }
                        catch {
                            Write-Warning "Failed to assign compliance policy $($policy.displayName): $_"
                        }
                    }
                }

                Write-Host "`n$ringName deployment completed successfully!" -ForegroundColor Green
            }
            catch {
                Write-Error "Error during policy assignment: $_"
            }
        }
        else {
            Write-Host "[DRY RUN] Would assign all NLBaseline policies to configured groups" -ForegroundColor Cyan
        }
    }

    Write-Host "`nDeployment completed!" -ForegroundColor Green
}