functions/Update-PolicyAssignmentCsvParameterFile.ps1
|
function Update-PolicyAssignmentCsvParameterFile { <# Updates an existing EPAC policy assignment parameter CSV from a generated CSV. Reconciles a CSV generated by Build-PolicyDocumentation with an existing assignment parameter CSV. Rows are matched by name and referencePath. Generated metadata is refreshed. Existing columns ending in Effect or Parameters and existing custom columns are preserved. Policies no longer present in the generated CSV are removed, and newly generated policies are added with their generated defaults. Path to a current CSV generated by Build-PolicyDocumentation. Path to the existing assignment parameter CSV to update in place. ./Build-PolicyDocumentation.ps1 -Interactive:$false ./Update-PolicyAssignmentCsvParameterFile.ps1 ` -GeneratedCsvPath ./Outputs/policy-documentation/security-baseline.csv ` -ParameterCsvPath ./Definitions/policyAssignments/security-baseline-parameters.csv ./Update-PolicyAssignmentCsvParameterFile.ps1 ` -GeneratedCsvPath ./Outputs/policy-documentation/security-baseline.csv ` -ParameterCsvPath ./Definitions/policyAssignments/security-baseline-parameters.csv ` -WhatIf #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param ( [Parameter(Mandatory = $true)] [string] $GeneratedCsvPath, [Parameter(Mandatory = $true)] [string] $ParameterCsvPath ) $generatedPath = (Resolve-Path -LiteralPath $GeneratedCsvPath -ErrorAction Stop).Path $parameterPath = (Resolve-Path -LiteralPath $ParameterCsvPath -ErrorAction Stop).Path if (-not (Test-Path -LiteralPath $generatedPath -PathType Leaf)) { throw "Generated CSV path '$GeneratedCsvPath' is not a file." } if (-not (Test-Path -LiteralPath $parameterPath -PathType Leaf)) { throw "Parameter CSV path '$ParameterCsvPath' is not a file." } if ($generatedPath -eq $parameterPath) { throw "GeneratedCsvPath and ParameterCsvPath must reference different files." } [object[]] $generatedRows = @(Import-Csv -LiteralPath $generatedPath -ErrorAction Stop) [object[]] $existingRows = @(Import-Csv -LiteralPath $parameterPath -ErrorAction Stop) $mergeResult = Merge-PolicyAssignmentCsvParameterRow ` -GeneratedRows $generatedRows ` -ExistingRows $existingRows if ($PSCmdlet.ShouldProcess($parameterPath, "Reconcile policy assignment parameter CSV")) { $targetBytes = [System.IO.File]::ReadAllBytes($parameterPath) $hasUtf8Bom = $targetBytes.Length -ge 3 -and $targetBytes[0] -eq 0xEF -and $targetBytes[1] -eq 0xBB -and $targetBytes[2] -eq 0xBF $encoding = [System.Text.UTF8Encoding]::new($hasUtf8Bom) $targetText = $encoding.GetString($targetBytes) $lineEnding = if ($targetText.Contains("`r`n")) { "`r`n" } else { "`n" } $temporaryPath = "$parameterPath.$PID.$([guid]::NewGuid().ToString("N")).tmp" try { [string[]] $csvLines = @($mergeResult.Rows | ConvertTo-Csv) $csvText = ($csvLines -join $lineEnding) + $lineEnding [System.IO.File]::WriteAllText($temporaryPath, $csvText, $encoding) [System.IO.File]::Move($temporaryPath, $parameterPath, $true) } finally { if (Test-Path -LiteralPath $temporaryPath) { Remove-Item -LiteralPath $temporaryPath -Force } } Write-Information ( "Updated '$parameterPath': added {0}, refreshed {1}, removed {2} row(s)." -f $mergeResult.AddedCount, $mergeResult.UpdatedCount, $mergeResult.RemovedCount ) -InformationAction Continue } } |