У меня есть установщик Inno Setup, который работает в очень тихом режиме (он работает).
Но когда я запускаю установщик Inno Setup через сценарий PowerShell с правами администратора, я получаю бесконечное выполнение. Кроме того, следующий код сценария (SetEnvironmentVariable) не выполняется даже после успешной установки.
$installerArguments = $requiredInstallerArguments + $additionalInstallerArguments
Start-Process -FilePath $installerFile.FullName -ArgumentList $installerArguments -Wait
[Environment]::SetEnvironmentVariable('WebPort', (GetValueByKey -array $additionalInstallerArguments -key "/webport"), [EnvironmentVariableTarget]::Machine)
Почему это происходит и как это исправить?





Иногда мне приходится использовать метод .WaitForExit()
$Process = Start-Process -FilePath $installerFile.FullName -ArgumentList $installerArguments -PassThru
$Process.WaitForExit()
Start-Process ... -Wait ведет себя иначе, чем (Start-Process ... -PassThru).WaitForExit() / Start-Process ... -PassThru | Wait-Process: первый ждет завершения всего дерева дочерних процессов, тогда как второй возвращается после завершения непосредственного дочернего процесса (см. Проблема GitHub № 15555). Таким образом, если установщик порождает дочерний процесс, который продолжает работать после выхода из установщика, -Wait не вернется, пока этот дочерний процесс не завершится.
В SysInternals Process Monitor вы можете использовать Инструменты->Дерево процессов, чтобы просмотреть эти деревья процессов.
В дополнение к полезному ответу Prodige69:
Другой способ дождаться только msiexec.exe (и дочерних процессов, запускаемых из него синхронно, если таковые имеются), а не всего его дочернего дерева процессов (msiexec.exe плюс любые дочерние процессы, запущенные из него асинхронно, что и является причиной проблемы здесь), — использовать прямое вызов или вызов через cmd.exe /c:
Это синтаксически более простые альтернативы использованию (Start-Process ... -PassThru).WaitForExit() или Start-Process ... -PassThru | Wait-Process, которые также автоматически отражают код завершения процесса msiexec в автоматической переменной $LASTEXITCODE :
Примечание. Я использую msiexec.exe в примерах команд ниже, но то же самое применимо и к любому установщику; в вашем случае, при использовании техники прямого призыва, замените & $installerFile.FullName на msiexec, при использовании техники cmd.exe /c замените "$($installerFile.FullName)"
# To build an argument list *programmatically*, create an *array*
$installerArguments = '/i', 'sample.msi', '/qn'
# Executes *synchronously*, due to `| Out-Null`
# Process exit code is reported in $LASTEXITCODE afterwards.
# Equivalent of:
# msiexec /i sample.msi /qn | Out-Null
msiexec $installerArguments | Out-Null
cmd /c, который позволяет явно управлять цитированием, что необходимо для значений свойств, требующих частичного цитирования:# Here, encode all arguments in a *single string*, using embedded double-quoting.
$installerArgumentList = '/i sample.msi /qn PROP = "Value with spaces"'
# Executes *synchronously*, due to `cmd /c`
# Process exit code is reported in $LASTEXITCODE afterwards.
cmd /c "msiexec $installerArguments"
См. этот ответ для получения дополнительной информации.