Install-FromManifest: WaitTimeoutSec for EXE entries (lib v2.5)
UDC_Setup.exe is a WiX Burn bootstrapper that installs the underlying MSI cleanly with /quiet but the wrapper process never exits - waits on a bundled child service that doesn't return control. Empirically: DisplayVersion=1.0.34 + UDC.exe present in C:\Program Files\UDC after ~30s, but Process.WaitForExit blocks indefinitely (>5 min observed). EXE handler now honors optional WaitTimeoutSec on the manifest entry. After timeout, kills the wrapper, re-runs Test-Installed; if detection passes, treats as success (rc 0); if fail, surfaces as -2 (distinct from -1 Process.Start failure). Default unset = old behavior (block forever via WaitForExit) so existing entries unaffected. Pairs with UDC manifest entry update on the v2 share: InstallArgs: "West Jefferson" 9999 -> /quiet /norestart + WaitTimeoutSec: 120 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,12 @@ $ErrorActionPreference = 'Continue'
|
|||||||
# logged; manifests tagged with a newer MINOR are fine.
|
# logged; manifests tagged with a newer MINOR are fine.
|
||||||
#
|
#
|
||||||
# Changelog:
|
# Changelog:
|
||||||
|
# 2.5 - Type=EXE handler honors optional WaitTimeoutSec on the manifest
|
||||||
|
# entry. WiX Burn bootstrappers (UDC_Setup.exe) install the MSI
|
||||||
|
# successfully but the wrapper process never exits (waits on a
|
||||||
|
# bundled child service). With WaitTimeoutSec set, kill the
|
||||||
|
# wrapper after timeout, re-check Test-Installed - if pass,
|
||||||
|
# treat as success (rc 0); if fail, surface as -2.
|
||||||
# 2.4 - Type=EXE handler stages network-share EXEs to a local temp dir
|
# 2.4 - Type=EXE handler stages network-share EXEs to a local temp dir
|
||||||
# before invoking Process.Start. SYSTEM-context Process.Start
|
# before invoking Process.Start. SYSTEM-context Process.Start
|
||||||
# fails with "Access is denied" on \\share or mapped-drive EXE
|
# fails with "Access is denied" on \\share or mapped-drive EXE
|
||||||
@@ -52,7 +58,7 @@ $ErrorActionPreference = 'Continue'
|
|||||||
# 2.0 - initial Stage 2a: PS1/BAT/File/Registry/INF action types,
|
# 2.0 - initial Stage 2a: PS1/BAT/File/Registry/INF action types,
|
||||||
# Always/MarkerFile/ValueMatches/pnputil detection, PCTypes filter
|
# Always/MarkerFile/ValueMatches/pnputil detection, PCTypes filter
|
||||||
$LIB_MANIFEST_MAJOR = 2
|
$LIB_MANIFEST_MAJOR = 2
|
||||||
$LIB_MANIFEST_MINOR = 4
|
$LIB_MANIFEST_MINOR = 5
|
||||||
|
|
||||||
$logDir = Split-Path -Parent $LogFile
|
$logDir = Split-Path -Parent $LogFile
|
||||||
if (-not (Test-Path $logDir)) {
|
if (-not (Test-Path $logDir)) {
|
||||||
@@ -293,10 +299,36 @@ function Invoke-InstallerAction {
|
|||||||
if ($App.InstallArgs) { $psi.Arguments = $App.InstallArgs }
|
if ($App.InstallArgs) { $psi.Arguments = $App.InstallArgs }
|
||||||
Write-InstallLog " exe: $runPath"
|
Write-InstallLog " exe: $runPath"
|
||||||
if ($App.InstallArgs) { Write-InstallLog " args: $($App.InstallArgs)" }
|
if ($App.InstallArgs) { Write-InstallLog " args: $($App.InstallArgs)" }
|
||||||
|
# Optional WaitTimeoutSec on the manifest entry: some EXE wrappers
|
||||||
|
# complete the install but don't exit themselves (UDC_Setup.exe is a
|
||||||
|
# WiX Burn bootstrapper that hangs post-install waiting on a child
|
||||||
|
# service that never returns control). When set, kill the wrapper
|
||||||
|
# after the timeout AND re-check detection - if installed, treat as
|
||||||
|
# success (rc 0); else surface as failure. Default unset = old
|
||||||
|
# behavior (block forever via WaitForExit).
|
||||||
|
$waitTimeoutMs = if ($App.WaitTimeoutSec) { [int]$App.WaitTimeoutSec * 1000 } else { -1 }
|
||||||
try {
|
try {
|
||||||
$proc = [System.Diagnostics.Process]::Start($psi)
|
$proc = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
if ($waitTimeoutMs -gt 0) {
|
||||||
|
$exited = $proc.WaitForExit($waitTimeoutMs)
|
||||||
|
if (-not $exited) {
|
||||||
|
Write-InstallLog " WaitTimeoutSec=$($App.WaitTimeoutSec) reached - killing wrapper, will re-check detection" 'WARN'
|
||||||
|
try { $proc.Kill(); $proc.WaitForExit(5000) | Out-Null } catch {}
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
if (Test-Installed -App $App) {
|
||||||
|
Write-InstallLog " detection passes post-kill - treating as success"
|
||||||
|
$exitCode = 0
|
||||||
|
} else {
|
||||||
|
Write-InstallLog " detection still missing post-kill - failure" 'ERROR'
|
||||||
|
$exitCode = -2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$exitCode = $proc.ExitCode
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$proc.WaitForExit()
|
$proc.WaitForExit()
|
||||||
$exitCode = $proc.ExitCode
|
$exitCode = $proc.ExitCode
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-InstallLog " Process.Start failed: $_" 'ERROR'
|
Write-InstallLog " Process.Start failed: $_" 'ERROR'
|
||||||
$exitCode = -1
|
$exitCode = -1
|
||||||
|
|||||||
Reference in New Issue
Block a user