从Powershell脚本安装Python

huangapple go评论90阅读模式
英文:

Install Python from Powershell script

问题

以下是翻译好的内容:

以下命令在以管理员身份从 PowerShell 命令行运行时,可以成功在 Windows 11 上安装 Python:

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

但是,当将相同的命令放在一个名为 myinstallscript.ps1 的脚本中,并从 PowerShell 命令行调用该脚本时(使用 .\myinstallscript.ps1),安装会失败,而且没有抛出任何错误。

以下是相关的脚本代码,包括在脚本中调用时不起作用的相同命令:

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\"

为了成功执行 c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0 命令,myinstallscript.ps1 中需要使用特定的语法。如果安装由于某种未预料到的原因失败,需要使用特定的语法使命令能够优雅地中断程序并显示有用的错误消息。

英文:

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?

答案1

得分: 1

当PowerShell调用外部程序(如python-3.11.4-amd64.exe)时,它通过自动变量$LASTEXITCODE报告它们的进程退出代码。按照惯例,外部程序使用值0表示成功,使用任何非零的退出代码表示失败。

然而,只有当外部程序以同步方式执行(即阻塞调用者直到程序终止)时,PowerShell才能报告退出代码,而PowerShell默认以异步方式执行GUI(子系统)应用程序(即启动外部程序并立即将控制权返回给调用者)。

通常,像python-3.11.4-amd64.exe这样的安装程序是GUI应用程序,因此需要额外的努力使调用变为同步,以便您的脚本(a)等待安装完成,并且(b)可以通过$LASTEXITCODE检查成功与失败。

有几种方法可以使GUI应用程序的调用变为同步。
在这种情况下 - 对于还报告有意义的退出代码的GUI应用程序 - 最简单的解决方案是将其_管道到Write-Output_

"About to install Python."
# 注意末尾的 `| Write-Output`,它使调用变为同步,并填充 $LASTEXITCODE 变量。
c:/temp/python-3.11.4-amd64.exe /quiet InstallAllUsers=0 InstallLauncherAllUsers=0 PrependPath=1 Include_test=0 | Write-Output

# 检查安装是否失败,如果是,则退出。
if ($LASTEXITCODE -ne 0) {
  Write-Error "Installation failed unexpectedly; exit code is $LASTEXITCODE."
  exit $LASTEXITCODE
}

有关该技术的解释以及其他替代方法,请参见此答案

英文:
  • 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.

huangapple
  • 本文由 发表于 2023年8月9日 05:31:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76863325.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定