Public/Import-NLBaselineCABaselineDebug.ps1

function Import-NLBaselineCABaselineDebug {
    <#
    .SYNOPSIS
    Import only policies that failed in previous import (Debug mode)
     
    .DESCRIPTION
    Reads the latest import log and imports only the policies that failed or were skipped.
    This allows quick retry of problematic policies without re-importing everything.
     
    .EXAMPLE
    Import-NLBaselineCABaselineDebug
    #>

    
    [CmdletBinding()]
    param()
    
    try {
        # Get module configuration
        $moduleConfigPath = Get-ConfigPath
        if (-not (Test-Path $moduleConfigPath)) {
            Write-Error "Module configuration not found. Run Quick Start first."
            return
        }
        
        $moduleConfig = Get-Content $moduleConfigPath | ConvertFrom-Json
        $storagePath = $moduleConfig.StoragePath
        
        if (-not (Test-Path $storagePath)) {
            Write-Error "Storage path not found: $storagePath. Run Quick Start to configure."
            return
        }
        
        # Check for logs
        $logsPath = Join-Path $storagePath "Logs"
        if (-not (Test-Path $logsPath)) {
            Write-Error "No Logs folder found. Run a regular import first to generate logs."
            return
        }
        
        # Find latest import log
        $logFiles = Get-ChildItem -Path $logsPath -Filter "Import-*.log" | Sort-Object LastWriteTime -Descending
        if (-not $logFiles -or $logFiles.Count -eq 0) {
            Write-Error "No import logs found. Run a regular import first."
            return
        }
        
        $latestLog = $logFiles[0]
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host " DEBUG MODE - IMPORT FAILED POLICIES" -ForegroundColor Cyan
        Write-Host "========================================" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "Using log file: $($latestLog.Name)" -ForegroundColor Yellow
        Write-Host "Log date: $($latestLog.LastWriteTime)" -ForegroundColor Gray
        Write-Host ""
        
        # Read log file and extract failed policy names
        $logContent = Get-Content $latestLog.FullName -Raw
        $failedPolicies = @()
        
        # Extract policy names from error lines
        if ($logContent -match "(?smi)ERROR SUMMARY:.*?DETAILED ERROR LOG:") {
            $errorSection = $Matches[0]
            
            # Match patterns like "Failed to create CA012..." or "Skipped CA005..."
            $errorMatches = [regex]::Matches($errorSection, "(?:Failed to create|Skipped)\s+([A-Z0-9\-]+(?:-[A-Za-z0-9\-]+)*)")
            foreach ($match in $errorMatches) {
                $policyName = $match.Groups[1].Value
                if ($policyName -and $failedPolicies -notcontains $policyName) {
                    $failedPolicies += $policyName
                }
            }
        }
        
        # Also check summary JSON if available
        $summaryPath = Join-Path $storagePath "baseline-import-summary.json"
        if (Test-Path $summaryPath) {
            try {
                $summary = Get-Content $summaryPath | ConvertFrom-Json
                if ($summary.Errors) {
                    foreach ($error in $summary.Errors) {
                        # Extract policy name from error message
                        if ($error -match "(?:Failed to create|Skipped)\s+([A-Z0-9\-]+(?:-[A-Za-z0-9\-]+)*)") {
                            $policyName = $Matches[1]
                            if ($policyName -and $failedPolicies -notcontains $policyName) {
                                $failedPolicies += $policyName
                            }
                        }
                    }
                }
            }
            catch {
                Write-Host " Warning: Could not read summary file: $_" -ForegroundColor Yellow
            }
        }
        
        if ($failedPolicies.Count -eq 0) {
            Write-Host "No failed policies found in log file." -ForegroundColor Yellow
            Write-Host "All policies were successful or log format is different." -ForegroundColor Gray
            return
        }
        
        Write-Host "Found $($failedPolicies.Count) failed/skipped policies:" -ForegroundColor Yellow
        foreach ($policy in $failedPolicies) {
            Write-Host " - $policy" -ForegroundColor Gray
        }
        Write-Host ""
        
        # Get baseline path
        $baselinePath = Join-Path $storagePath "Baseline"
        if (-not (Test-Path $baselinePath)) {
            Write-Error "Baseline folder not found: $baselinePath"
            return
        }
        
        # Find matching policy files
        $policyFiles = @()
        foreach ($policyName in $failedPolicies) {
            # Try to find file matching the policy name
            $matchingFiles = Get-ChildItem -Path $baselinePath -Filter "*.json" | Where-Object {
                $content = Get-Content $_.FullName -Raw | ConvertFrom-Json
                if ($content.displayName -eq $policyName) {
                    return $true
                }
                # Also check if filename contains policy name
                if ($_.Name -like "*$policyName*") {
                    return $true
                }
                return $false
            }
            
            if ($matchingFiles) {
                $policyFiles += $matchingFiles[0]
            }
            else {
                Write-Host " Warning: Could not find file for policy: $policyName" -ForegroundColor Yellow
            }
        }
        
        if ($policyFiles.Count -eq 0) {
            Write-Error "No matching policy files found for failed policies."
            return
        }
        
        Write-Host "Found $($policyFiles.Count) matching policy file(s)" -ForegroundColor Green
        Write-Host ""
        
        # Ask for confirmation
        Write-Host "This will import only the failed policies listed above." -ForegroundColor Yellow
        Write-Host ""
        $confirm = Read-Host "Continue? (Y/N)"
        
        if ($confirm -ne "Y" -and $confirm -ne "y") {
            Write-Host "Cancelled." -ForegroundColor Yellow
            return
        }
        
        Write-Host ""
        Write-Host "Starting debug import..." -ForegroundColor Cyan
        Write-Host ""
        
        # Now call the regular import function but with only these files
        # We'll need to modify the approach - instead, we'll manually process these files
        # 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
        }
        
        # Ask for status
        Write-Host "Policy status:" -ForegroundColor Yellow
        Write-Host " 1. enabledForReportingButNotEnforced (Report-only)" -ForegroundColor White
        Write-Host " 2. enabled (Enabled)" -ForegroundColor White
        Write-Host ""
        $statusChoice = Read-Host "Select status (1 or 2, default: 1)"
        $policyStatus = if ($statusChoice -eq "2") { "enabled" } else { "enabledForReportingButNotEnforced" }
        
        # Ask if create in M365
        Write-Host ""
        $createInM365 = Read-Host "Create policies in Microsoft 365? (Y/N, default: Y)"
        if ([string]::IsNullOrWhiteSpace($createInM365)) {
            $createInM365 = "Y"
        }
        
        # Process each file
        $importedCount = 0
        $createdCount = 0
        $errors = @()
        
        foreach ($file in $policyFiles) {
            try {
                Write-Host "Processing: $($file.Name)" -ForegroundColor Cyan
                
                $policy = Get-Content $file.FullName -Raw | ConvertFrom-Json
                
                # Use the same logic as Import-NLBaselineCABaseline but simplified
                # For now, just call the main import function with a filter
                # Actually, we need to import the function logic or call it differently
                # Let's create a simplified version that processes these specific files
                
                # This is a simplified version - in practice, you'd want to reuse the main import logic
                Write-Host " Policy: $($policy.displayName)" -ForegroundColor White
                
                if ($createInM365 -eq 'Y' -or $createInM365 -eq 'y') {
                    # Build policy object (simplified - reuse main function logic if possible)
                    $policyToCreate = @{
                        displayName = $policy.displayName
                        state = $policyStatus
                        conditions = $policy.conditions
                        grantControls = $policy.grantControls
                    }
                    
                    if ($policy.sessionControls) {
                        $policyToCreate.sessionControls = $policy.sessionControls
                    }
                    
                    # Ensure grantControls exists
                    if (-not $policyToCreate.grantControls) {
                        $policyToCreate.grantControls = @{
                            "@odata.type" = "#microsoft.graph.conditionalAccessGrantControls"
                            "operator" = "OR"
                            "builtInControls" = @("requireCompliantDevice")
                            "customAuthenticationFactors" = @()
                            "termsOfUse" = @()
                            "authenticationStrength" = $null
                        }
                    }
                    
                    $body = $policyToCreate | ConvertTo-Json -Depth 20
                    
                    try {
                        Invoke-MgGraphRequest -Method POST `
                            -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" `
                            -Body $body `
                            -ContentType "application/json" `
                            -ErrorAction Stop
                        
                        Write-Host " Created in M365: $($policyToCreate.displayName)" -ForegroundColor Green
                        $createdCount++
                    }
                    catch {
                        $errorMessage = $_.Exception.Message
                        Write-Host " Failed to create: $errorMessage" -ForegroundColor Red
                        $errors += "Failed to create $($policyToCreate.displayName): $errorMessage"
                    }
                }
                
                $importedCount++
            }
            catch {
                Write-Host " Error processing $($file.Name): $_" -ForegroundColor Red
                $errors += "Error processing $($file.Name): $_"
            }
        }
        
        Write-Host ""
        Write-Host "========================================" -ForegroundColor Green
        Write-Host " DEBUG IMPORT COMPLETED" -ForegroundColor Green
        Write-Host "========================================" -ForegroundColor Green
        Write-Host "Processed: $importedCount policy/policies" -ForegroundColor White
        if ($createInM365 -eq 'Y' -or $createInM365 -eq 'y') {
            Write-Host "Created in M365: $createdCount policy/policies" -ForegroundColor White
        }
        Write-Host ""
        
        if ($errors.Count -gt 0) {
            Write-Host "Errors encountered:" -ForegroundColor Yellow
            foreach ($err in $errors) {
                Write-Host " - $err" -ForegroundColor Red
            }
            Write-Host ""
        }
    }
    catch {
        Write-Error "Error in debug import: $_"
    }
}