Public/Sync-NLBaselineWorkspace.ps1

<#
.SYNOPSIS
    Synchronizes workspace with module resources
.DESCRIPTION
    Ensures all resources from the module are copied to the workspace, updating any missing or outdated files
    This is useful when the module is updated and you want to sync new resources to your workspace
.EXAMPLE
    Sync-NLBaselineWorkspace
#>

function Sync-NLBaselineWorkspace {
    [CmdletBinding()]
    param(
        [switch]$Force
    )

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

    if (-not (Test-Path -Path $workspacePath)) {
        Write-Error "Workspace path does not exist: $workspacePath"
        return
    }

    Write-Host "`nSynchronizing NLBaseline workspace with module resources`n" -ForegroundColor Cyan
    Write-Host "Workspace: $workspacePath" -ForegroundColor White

    $modulePath = $PSScriptRoot -replace 'Public$', ''
    $syncedItems = 0

    # Sync Baseline files
    Write-Host "`nSyncing Baseline files..." -ForegroundColor Yellow
    $resourcesPath = Join-Path -Path $modulePath -ChildPath "Resources\Baseline"
    $baselineDest = Join-Path -Path $workspacePath -ChildPath "Baseline"
    if (Test-Path -Path $resourcesPath) {
        if (-not (Test-Path -Path $baselineDest)) {
            New-Item -ItemType Directory -Path $baselineDest -Force | Out-Null
        }
        $baselineFiles = Get-ChildItem -Path $resourcesPath -Filter "*.json"
        foreach ($file in $baselineFiles) {
            $destPath = Join-Path -Path $baselineDest -ChildPath $file.Name
            if ($Force -or -not (Test-Path -Path $destPath) -or (Get-Item $file.FullName).LastWriteTime -gt (Get-Item $destPath).LastWriteTime) {
                if ($file.Name -eq 'WMISettings.json') {
                    try {
                        $wmiSettings = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
                        $baselineWMI = Convert-WMISettingsToBaseline -WMISettings $wmiSettings
                        $baselineWMI | ConvertTo-Json -Depth 10 | Set-Content -Path $destPath -Force
                        Write-Host " Synced: $($file.Name)" -ForegroundColor Green
                        $syncedItems++
                    }
                    catch {
                        Write-Warning "Failed to sync WMISettings.json: $_"
                    }
                }
                else {
                    Copy-Item -Path $file.FullName -Destination $destPath -Force
                    Write-Host " Synced: $($file.Name)" -ForegroundColor Green
                    $syncedItems++
                }
            }
        }
    }

    # Sync Exploit Protection files
    Write-Host "`nSyncing Exploit Protection files..." -ForegroundColor Yellow
    $exploitPath = Join-Path -Path $modulePath -ChildPath "Resources\ExploitProtections"
    $exploitDest = Join-Path -Path $workspacePath -ChildPath "ExploitProtections"
    if (Test-Path -Path $exploitPath) {
        if (-not (Test-Path -Path $exploitDest)) {
            New-Item -ItemType Directory -Path $exploitDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$exploitPath", $exploitDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced Exploit Protection files" -ForegroundColor Green
        }
    }

    # Sync Event Viewer Custom Views
    Write-Host "`nSyncing Event Viewer Custom Views..." -ForegroundColor Yellow
    $eventViewerPath = Join-Path -Path $modulePath -ChildPath "Resources\EventViewerCustomViews"
    $eventViewerDest = Join-Path -Path $workspacePath -ChildPath "EventViewerCustomViews"
    if (Test-Path -Path $eventViewerPath) {
        if (-not (Test-Path -Path $eventViewerDest)) {
            New-Item -ItemType Directory -Path $eventViewerDest -Force | Out-Null
        }
        Copy-Item -Path "$eventViewerPath\*.xml" -Destination $eventViewerDest -Force
        $syncedItems++
        Write-Host " Synced Event Viewer Custom Views" -ForegroundColor Green
    }

    # Sync Country IP Data
    Write-Host "`nSyncing Country IP Data..." -ForegroundColor Yellow
    $countryIPPath = Join-Path -Path $modulePath -ChildPath "Resources\CountryIPsData"
    $countryIPDest = Join-Path -Path $workspacePath -ChildPath "CountryIPsData"
    if (Test-Path -Path $countryIPPath) {
        if (-not (Test-Path -Path $countryIPDest)) {
            New-Item -ItemType Directory -Path $countryIPDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$countryIPPath", $countryIPDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced Country IP Data" -ForegroundColor Green
        }
    }

    # Sync Mitigations CSV
    Write-Host "`nSyncing Process Mitigations..." -ForegroundColor Yellow
    $mitigationsPath = Join-Path -Path $modulePath -ChildPath "Resources\Mitigations"
    $mitigationsDest = Join-Path -Path $workspacePath -ChildPath "Mitigations"
    if (Test-Path -Path $mitigationsPath) {
        if (-not (Test-Path -Path $mitigationsDest)) {
            New-Item -ItemType Directory -Path $mitigationsDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$mitigationsPath", $mitigationsDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced Process Mitigations" -ForegroundColor Green
        }
    }

    # Sync Intune Files
    Write-Host "`nSyncing Intune Files..." -ForegroundColor Yellow
    $intuneFilesPath = Join-Path -Path $modulePath -ChildPath "Resources\IntuneFiles"
    $intuneFilesDest = Join-Path -Path $workspacePath -ChildPath "IntuneFiles"
    if (Test-Path -Path $intuneFilesPath) {
        if (-not (Test-Path -Path $intuneFilesDest)) {
            New-Item -ItemType Directory -Path $intuneFilesDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$intuneFilesPath", $intuneFilesDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced Intune Files" -ForegroundColor Green
        }
    }

    # Sync Winget AutoUpdate ADMX/ADML files
    Write-Host "`nSyncing Winget AutoUpdate files..." -ForegroundColor Yellow
    $wingetPath = Join-Path -Path $modulePath -ChildPath "Resources\WingetAutoUpdate"
    $wingetDest = Join-Path -Path $workspacePath -ChildPath "WingetAutoUpdate"
    if (Test-Path -Path $wingetPath) {
        if (-not (Test-Path -Path $wingetDest)) {
            New-Item -ItemType Directory -Path $wingetDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$wingetPath", $wingetDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced Winget AutoUpdate files" -ForegroundColor Green
        }
    }

    # Sync CIS Benchmark files if available in module resources
    Write-Host "`nSyncing CIS Benchmark files..." -ForegroundColor Yellow
    $cisPath = Join-Path -Path $modulePath -ChildPath "Resources\CIS"
    $cisDest = Join-Path -Path $workspacePath -ChildPath "CIS"
    if (Test-Path -Path $cisPath) {
        if (-not (Test-Path -Path $cisDest)) {
            New-Item -ItemType Directory -Path $cisDest -Force | Out-Null
        }
        # Use robocopy for better reliability
        $robocopyArgs = @("$cisPath", $cisDest, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NP", "/R:2", "/W:1")
        $null = & robocopy @robocopyArgs 2>&1
        if ($LASTEXITCODE -le 7) {
            $syncedItems++
            Write-Host " Synced CIS Benchmark files" -ForegroundColor Green
        }
    }
    else {
        Write-Host " CIS Benchmark files not found in module resources" -ForegroundColor Yellow
        Write-Host " Note: Download CIS Windows 11 Benchmark from https://www.cisecurity.org" -ForegroundColor Gray
        Write-Host " Extract to: $cisDest\Windows-11-CIS-devel\tasks" -ForegroundColor Gray
    }

    # Ensure ring configuration template exists
    Write-Host "`nChecking ring configuration..." -ForegroundColor Yellow
    $deploymentPath = Join-Path -Path $workspacePath -ChildPath "Deployment"
    if (-not (Test-Path -Path $deploymentPath)) {
        New-Item -ItemType Directory -Path $deploymentPath -Force | Out-Null
    }
    $ringConfigPath = Join-Path -Path $deploymentPath -ChildPath "ring-configuration.json"
    if (-not (Test-Path -Path $ringConfigPath)) {
        try {
            $ringTemplate = Get-RingConfigurationTemplate
            $ringTemplate | ConvertTo-Json -Depth 10 | Set-Content -Path $ringConfigPath -Encoding UTF8 -Force
            Write-Host " Created ring-configuration.json template" -ForegroundColor Green
            $syncedItems++
        }
        catch {
            Write-Warning "Failed to create ring configuration template: $_"
        }
    }
    else {
        Write-Host " Ring configuration already exists" -ForegroundColor Gray
    }

    Write-Host "`nSynchronization completed! Synced $syncedItems items." -ForegroundColor Green
}