Private/New-Win32ToolkitSparseConfig.ps1
|
function New-Win32ToolkitSparseConfig { <# .SYNOPSIS Builds a SPARSE PSADT config.psd1 (text) from an org template — only the keys the template overrides, nothing else. .DESCRIPTION PSADT loads its own signed module-default config.psd1 first, then SUPERIMPOSES the project's Config\config.psd1 over it key-by-key (Import-ADTModuleDataFile → Update-ADTImportedDataValues in PSAppDeployToolkit.psm1). So the project file need only carry the deltas; every key it omits keeps the module default. This replaces the previous approach of regex-patching a full copy of the default file, which drifted silently whenever PSADT reordered or renamed config text (see knowledge-base TODO "org template → data", F1). Two hard rules of the superimpose that shape this emitter: * An empty / whitespace value is IGNORED by PSADT (it cannot blank a default). So we OMIT any key the template doesn't set, rather than emit an empty string. * The signature/tamper check applies only to the MODULE's default file, never the caller's — an unsigned sparse project config is legal. The returned text must REPLACE the project's scaffolded full config.psd1 (do not write it alongside — a leftover full file would shadow module defaults with stale values). .PARAMETER Template The org-template object (New-OrgTemplate schema). Read defensively — older templates may lack newer fields. .OUTPUTS [string] the config.psd1 text (LF/CRLF as written by the caller; caller writes UTF-8 BOM). #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [PSCustomObject]$Template ) # psd1 single-quoted literal, single quotes doubled. $env* tokens inside (e.g. LogPath) are # preserved verbatim — PSADT expands them itself at runtime, so a literal is exactly right. function Format-Psd1String { param([string]$s) "'" + ($s -replace "'", "''") + "'" } # Defensive field read — returns $null for a missing property on an older-schema template. function Get-Field { param([PSCustomObject]$o, [string]$name) if ($o -and $o.PSObject.Properties[$name]) { $o.$name } else { $null } } $toolkit = [ordered]@{} $ui = [ordered]@{} #── Toolkit ───────────────────────────────────────────────────────── $company = Get-Field $Template 'CompanyName' if (-not [string]::IsNullOrWhiteSpace($company)) { $toolkit['CompanyName'] = Format-Psd1String $company } $logPath = Get-Field $Template 'LogPath' if (-not [string]::IsNullOrWhiteSpace($logPath)) { $toolkit['LogPath'] = Format-Psd1String $logPath } #── UI ────────────────────────────────────────────────────────────── # DialogStyle always emitted (Fluent default) so a project's dialog style is explicit and testable. $style = Get-Field $Template 'DialogStyle' if ([string]::IsNullOrWhiteSpace($style)) { $style = 'Fluent' } if ($style -notin @('Fluent', 'Classic')) { $style = 'Fluent' } $ui['DialogStyle'] = Format-Psd1String $style # FluentAccentColor is a BARE literal in config.psd1 (e.g. 0xFF0078D7) — never quoted, per the # PSADT config comment. Normalize any hex form to a canonical 0x literal; a value that isn't a # usable hex colour is OMITTED (degrades to the PSADT default) rather than emitted bare, which would # make the whole config.psd1 fail to parse on-device and abort the SYSTEM deploy. $accent = Get-Field $Template 'FluentAccentColor' if (-not [string]::IsNullOrWhiteSpace($accent)) { $accentLiteral = ConvertTo-Win32ToolkitAccentLiteral -Value $accent if ($accentLiteral) { $ui['FluentAccentColor'] = $accentLiteral } else { Write-Warning "Org template FluentAccentColor '$accent' is not a valid hex colour (use 0xAARRGGBB, #RRGGBB, or RRGGBB) — using the PSADT default accent." } } # LanguageOverride (C1): pin every dialog to one PSADT UI language; omit → per-user auto-detect. $lang = Get-Field $Template 'LanguageOverride' if (-not [string]::IsNullOrWhiteSpace($lang)) { $ui['LanguageOverride'] = Format-Psd1String $lang } #── assemble ──────────────────────────────────────────────────────── $nl = "`r`n" $sb = [System.Text.StringBuilder]::new() [void]$sb.Append('# Sparse PSADT config generated by win32-toolkit org template.').Append($nl) [void]$sb.Append('# Only the keys below override the PSADT module default (superimposed key-by-key).').Append($nl) [void]$sb.Append('# Do not hand-edit — regenerated whenever the org template is applied.').Append($nl) [void]$sb.Append('@{').Append($nl) if ($toolkit.Count -gt 0) { [void]$sb.Append(' Toolkit = @{').Append($nl) foreach ($k in $toolkit.Keys) { [void]$sb.Append(" $k = $($toolkit[$k])").Append($nl) } [void]$sb.Append(' }').Append($nl) } if ($ui.Count -gt 0) { [void]$sb.Append(' UI = @{').Append($nl) foreach ($k in $ui.Keys) { [void]$sb.Append(" $k = $($ui[$k])").Append($nl) } [void]$sb.Append(' }').Append($nl) } [void]$sb.Append('}').Append($nl) return $sb.ToString() } |