Public/Test-OpmApplicationFragment.ps1
|
<#
.SYNOPSIS Validate a PacKit application fragment before saving. .DESCRIPTION Checks the hard requirements PacKit enforces on load: - AppId is a valid braced UPPERCASE GUID - Name is non-empty - every package PackageId is a valid GUID - every assignment MsEntraGroupId is a valid GUID - no text field contains an XML-invalid control character (only TAB, CR and LF are allowed); such characters would make PacKit's XML reader reject the fragment And reports soft warnings (which do NOT fail validation): - a package Type that is not one of PacKit's recognised installer types Returns $true/$false by default. With -Detailed, returns an object with IsValid, Errors and Warnings so CI can log specifics. .EXAMPLE if (-not (Test-OpmApplicationFragment -Fragment $app)) { throw 'invalid fragment' } .EXAMPLE $report = Test-OpmApplicationFragment -Fragment $app -Detailed $report.Errors #> function Test-OpmApplicationFragment { [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory, ValueFromPipeline)] [psobject] $Fragment, [Parameter()] [switch] $Detailed ) process { $errors = New-Object System.Collections.Generic.List[string] $warnings = New-Object System.Collections.Generic.List[string] $schema = Get-OpmSchema if (-not (Test-OpmGuid -Value $Fragment.AppId)) { $errors.Add("AppId '$($Fragment.AppId)' is not a valid braced UPPERCASE GUID.") } if ([string]::IsNullOrEmpty($Fragment.Name)) { $errors.Add('Name is empty; PacKit requires a non-empty application name.') } foreach ($pkg in @($Fragment.Packages)) { if (-not (Test-OpmGuid -Value $pkg.PackageId)) { $errors.Add("Package PackageId '$($pkg.PackageId)' is not a valid braced UPPERCASE GUID.") } if (-not [string]::IsNullOrEmpty($pkg.Type) -and ($schema.PackageTypes -notcontains $pkg.Type)) { $warnings.Add("Package Type '$($pkg.Type)' is not one of PacKit's recognised installer types ($($schema.PackageTypes -join ', ')).") } } foreach ($asg in @($Fragment.IntuneAssignments)) { if (-not (Test-OpmGuid -Value $asg.MsEntraGroupId)) { $errors.Add("Assignment MsEntraGroupId '$($asg.MsEntraGroupId)' is not a valid braced UPPERCASE GUID.") } } # XML-invalid control characters in any text field would make PacKit's XML # reader reject the fragment (the writer would emit references like ). $textTargets = @(@{ Obj = $Fragment; Descriptors = $schema.App; Label = 'Application' }) foreach ($pkg in @($Fragment.Packages)) { $textTargets += @{ Obj = $pkg; Descriptors = $schema.Package; Label = 'Package' } foreach ($scan in @($pkg.WinGetScanResults)) { $textTargets += @{ Obj = $scan; Descriptors = $schema.WinGetScanResult; Label = 'WinGetScanResult' } } } foreach ($asg in @($Fragment.IntuneAssignments)) { $textTargets += @{ Obj = $asg; Descriptors = $schema.Assignment; Label = 'Assignment' } } foreach ($target in $textTargets) { foreach ($d in $target.Descriptors) { if ($d.Type -ne 'String') { continue } $text = [string](Get-OpmValueByPath -Object $target.Obj -Path $d.Path) if (-not (Test-OpmXmlSafeText -Value $text)) { $errors.Add("$($target.Label) field '$($d.Name)' contains an XML-invalid control character (only TAB, CR and LF are allowed); PacKit's XML reader would reject the fragment.") } } } $isValid = ($errors.Count -eq 0) if ($Detailed) { return [PSCustomObject]@{ IsValid = $isValid Errors = $errors.ToArray() Warnings = $warnings.ToArray() } } return $isValid } } |