private/Test-OSDeployWinPEStartupProfile.ps1
|
#Requires -PSEdition Core function Test-OSDeployWinPEStartupProfile { <# .SYNOPSIS Validates a WinPEStartup profile JSON file .DESCRIPTION Parses one WinPEStartup profile and verifies that it contains one non-empty JSON object using only supported properties and value types. Stored commands are not executed. Invalid content produces a terminating error that identifies the file. .PARAMETER Path Specifies the WinPEStartup profile JSON file to validate. .EXAMPLE PS> Test-OSDeployWinPEStartupProfile -Path 'C:\ProgramData\OSDeployCore\boot-assets\winpestartup-profiles\Deploy.json' Validates the selected WinPEStartup profile without executing its commands. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-09-11 #> [CmdletBinding()] param ( [Parameter(Mandatory)] [System.String] $Path ) if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { throw "WinPEStartup profile was not found: $Path" } try { $Profile = Get-Content -LiteralPath $Path -Raw -ErrorAction Stop | ConvertFrom-Json -NoEnumerate -ErrorAction Stop } catch { throw "Invalid WinPEStartup profile JSON '$Path': $($_.Exception.Message) Backslashes in JSON strings must be escaped as '\\'." } $BooleanKeys = @( 'Invoke-WinPEStartup:SkipOnScreenKeyboard' 'Invoke-WinPEStartup:ShowPnpDevices' 'Invoke-WinPEStartup:ShowPnpErrors' 'Invoke-WinPEStartup:SkipWiFi' 'Invoke-WinPEStartup:SkipIPConfig' 'Invoke-WinPEStartup:SkipUpdateOSDCloud' 'Invoke-WinPEStartup:InvokeStartupCommandNoExit' 'Invoke-WinPEStartup:InvokeMainCommandNoExit' 'Invoke-WinPEStartup:InvokeShutdownCommandNoExit' ) $ArrayKeys = @( 'Invoke-WinPEStartup:InstallModule' 'Invoke-WinPEStartup:InvokeStartupCommand' 'Invoke-WinPEStartup:InvokeMainCommand' 'Invoke-WinPEStartup:InvokeShutdownCommand' ) $ErrorActionKeys = @( 'Invoke-WinPEStartup:InvokeStartupCommandEA' 'Invoke-WinPEStartup:InvokeMainCommandEA' 'Invoke-WinPEStartup:InvokeShutdownCommandEA' ) $SupportedKeys = @($BooleanKeys + $ArrayKeys + $ErrorActionKeys) if ($Profile -isnot [System.Management.Automation.PSCustomObject] -or $Profile -is [System.Array]) { throw "Invalid WinPEStartup profile '$Path': The profile must contain one JSON object." } if (@($Profile.PSObject.Properties).Count -eq 0) { throw "Invalid WinPEStartup profile '$Path': The profile must contain at least one explicit setting." } foreach ($Property in $Profile.PSObject.Properties) { if ($Property.Name -notin $SupportedKeys) { throw "Invalid WinPEStartup profile '$Path': Unsupported property '$($Property.Name)'." } if ($Property.Name -in $BooleanKeys -and $Property.Value -isnot [System.Boolean]) { throw "Invalid WinPEStartup profile '$Path': '$($Property.Name)' must be a JSON boolean." } if ($Property.Name -in $ArrayKeys) { if ($Property.Value -isnot [System.Array]) { throw "Invalid WinPEStartup profile '$Path': '$($Property.Name)' must be a JSON array." } foreach ($Item in $Property.Value) { if ($Item -isnot [System.String] -or [System.String]::IsNullOrWhiteSpace($Item)) { throw "Invalid WinPEStartup profile '$Path': '$($Property.Name)' must contain only non-empty strings." } } } if ($Property.Name -in $ErrorActionKeys -and $Property.Value -notin @('Continue', 'Stop')) { throw "Invalid WinPEStartup profile '$Path': '$($Property.Name)' must be 'Continue' or 'Stop'." } } } |