From 7a67716fcc5916f59d9a37c16b3fd371dbbc34a8 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 3 Jun 2026 17:38:16 -0400 Subject: [PATCH] manifest engine: null-safe PS1 dispatch (accept Script or Installer, log resolved path) PS1 entries were crashing with a cryptic "Cannot bind LiteralPath because it is null" when the resolved script path came back null - the per-entry try/catch caught it (so the scope survived) but the cause was opaque. Now the PS1 branch accepts either Script or Installer, null-guards before Join-Path/Test-Path, and logs the resolved relative path, so a bad/empty entry is skipped with a clear "has no Script/Installer value" line instead of a null-bind throw. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../common/lib/Install-FromManifest.ps1 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 b/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 index 7d18531..ca2b746 100644 --- a/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 +++ b/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 @@ -354,9 +354,18 @@ function Invoke-InstallerAction { return [pscustomobject]@{ ExitCode = $proc.ExitCode; LogRef = $App.LogFile } } 'PS1' { - $scriptPath = Join-Path $InstallerRoot ($App.Script) + # Accept either Script or Installer as the relative path, and never + # feed a null into Join-Path/Test-Path (that throws a cryptic + # 'LiteralPath is null'). Log the resolved value so a bad/empty + # entry is obvious in the log instead of crashing the entry. + $rel = if ($App.Script) { $App.Script } elseif ($App.Installer) { $App.Installer } else { $null } + if ([string]::IsNullOrWhiteSpace([string]$rel)) { + Write-InstallLog (" PS1 entry '{0}' has no Script/Installer value (Script={1}, Installer={2}) - skipping" -f $App.Name, $App.Script, $App.Installer) 'ERROR' + return [pscustomobject]@{ ExitCode = -1; LogRef = $null } + } + $scriptPath = Join-Path $InstallerRoot $rel if (-not (Test-Path -LiteralPath $scriptPath)) { - Write-InstallLog " PS1 not found: $scriptPath" 'ERROR' + Write-InstallLog " PS1 not found: $scriptPath (from rel '$rel')" 'ERROR' return [pscustomobject]@{ ExitCode = -1; LogRef = $null } } $psi.FileName = 'powershell.exe'