0

The following command successfully installs Python on Windows 11 when run from the PowerShell command line as Administrator:

c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0

But when that same command is placed inside a script myinstallscript.ps1, and when that script is called from the PowerShell command line as .\myinstallscript.ps1 , the installation fails without throwing any error.

Here is the relevant script code, including the same command that does not work when it is invoked in a script:

Write-Output "About to create temp folder. "
New-Item -ItemType Directory -Force -Path C:\temp

Write-Output "About to set security protocol. "
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Write-Output "About to download Python executable to temp folder. "
Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.11.4/python-3.11.4-amd64.exe" -OutFile "c:/temp/python-3.11.4-amd64.exe"

Write-Output "About to install Python. "
c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0

Write-Output "About to append python to path temporarily. "
$env:Path += ";$($env:LOCALAPPDATA)\Programs\Python\Python311\;$($env:LOCALAPPDATA)\Programs\Python\Python311\Scripts\"

What specific syntax needs to be used in myinstallscript.ps1 in order to successfully execute the c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0 command? And what specific syntax would be needed in order for the command to gracefully break the program with a useful error message in the event that the installation fails for some unforeseen reason?

halfer
  • 19,824
  • 17
  • 99
  • 186
CodeMed
  • 9,527
  • 70
  • 212
  • 364
  • 1
    @mklement0 `Start-Process -Wait c:/temp/python-3.11.4-amd64.exe '/quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0'` works. Can you suggest a solution to [this downstream problem](https://stackoverflow.com/questions/76871462/set-itemproperty-is-failing-to-add-item-to-path)? – CodeMed Aug 09 '23 at 23:12

1 Answers1

1
  • When PowerShell calls external programs (such as python-3.11.4-amd64.exe), it reports their process exit code via the automatic $LASTEXITCODE variable. By convention, external programs signal success with value 0, and failure with any nonzero exit code.

  • However, PowerShell is only able to report the exit code if the external program executes synchronously (i.e., it blocks the caller until the program terminates), whereas PowerShell executes GUI(-subsystem) applications asynchronously by default (i.e., it launches the external program and immediately returns control to the caller).

Installers such as python-3.11.4-amd64.exe are typically GUI applications, so extra effort is needed to make the call synchronous, so that your script (a) awaits completion of the installation and (b) can check for success vs. failure via $LASTEXITCODE.

There are several ways to make invocation of a GUI application synchronous.
In the case at hand - for a GUI application that also reports a meaningful exit code - the simplest solution is to pipe to Write-Output.

"About to install Python. "
# Note the `| Write-Output` at the end, which makes the invocation 
# synchronous and populates the $LASTEXITCODE variable.
c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0 | Write-Output

# Check if the installation failed and exit, if so.
if ($LASTEXITCODE -ne 0) {
  Write-Error "Installation failed unexpectedly; exit code is $LASTEXITCODE."
  exit $LASTEXITCODE
}

See this answer for an explanation of the technique, as well as alternatives.

mklement0
  • 382,024
  • 64
  • 607
  • 775