通过批处理文件下载和安装 Python



我正在尝试使用PowerShell将Python 3安装程序从Python网站下载到特定目录中,然后在同一目录中静默运行/安装.exe文件,然后将适当的目录添加到系统的PATH变量中。

到目前为止,我已经想出了:

start cmd /k powershell -Command "(New-Object Net.WebClient).DownloadFile('https://www.python.org/ftp/python/3.6.2/python-3.6.2.exe', 'C:/Tools/python-3.6.2.exe')" &&
c:Toolspython-3.6.2.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 TargetDir=c:ToolsPython362 &&
setx path "%PATH%;C:ToolsPython362" /M

不幸的是,这不起作用。命令窗口将打开,然后立即退出。我已经分别运行了这些命令中的每一个,当我这样做时,它们会起作用。但是,当我尝试在同一文件中按顺序运行它们时,它不起作用。我该如何解决这个问题?

注意: 我相信问题源于使用&&,因为如果我使用&CMD 提示符将持续存在并执行。但是,这对我没有帮助,因为我需要在第一个命令完成后执行第二个命令,否则没有任何.exe文件可供运行第二个命令。我希望这只是一个语法错误,因为我对创建批处理文件和使用 Windows 命令行非常陌生。

我个人会在PowerShell中完成这一切。

我很想把它放在一个脚本中,就像这样:

[CmdletBinding()] Param(
$pythonVersion = "3.6.2"
$pythonUrl = "https://www.python.org/ftp/python/$pythonVersion/python-$pythonVersion.exe"
$pythonDownloadPath = 'C:Toolspython-$pythonVersion.exe'
$pythonInstallDir = "C:ToolsPython$pythonVersion"
)
(New-Object Net.WebClient).DownloadFile($pythonUrl, $pythonDownloadPath)
& $pythonDownloadPath /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 TargetDir=$pythonInstallDir
if ($LASTEXITCODE -ne 0) {
throw "The python installer at '$pythonDownloadPath' exited with error code '$LASTEXITCODE'"
}
# Set the PATH environment variable for the entire 
# machine (that is, for all users) to include 
# the Python install directory
[Environment]::SetEnvironmentVariable("PATH", "${env:path};${pythonInstallDir}", "Machine")

然后你可以从cmd调用脚本.exe如下所示:

powershell.exe -File X:PathtoInstall-Python.ps1

Param()块定义了 Python 版本的默认值、从中下载它的 URL、保存它的位置以及安装它的位置,但它允许您在有用时覆盖这些选项。您可以像这样传递这些参数:

powershell.exe -File X:PathtoInstall-Python.ps1 -version 3.4.0 -pythonInstallDir X:SomewhereElsePython3.4.0

也就是说,你绝对可以在纯PowerShell中做一个单行代码。从你的描述来看,我认为你不需要做start cmd /k前缀 - 你应该能够直接调用powershell.exe就像这样:

powershell -command "(New-Object Net.WebClient).DownloadFile('https://www.python.org/ftp/python/3.6.2/python-3.6.2.exe', 'C:/Tools/python-3.6.2.exe'); & c:Toolspython-3.6.2.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 TargetDir=c:ToolsPython362; [Environment]::SetEnvironmentVariable('PATH', ${env:path} + ';C:ToolsPython362', 'Machine')"

在PowerShell中完成所有操作,包括安装库。

# This is the link to download Python 3.6.7 from Python.org
# See https://www.python.org/downloads/
$pythonUrl = "https://www.python.org/ftp/python/3.6.7/python-3.6.7-amd64.exe"
# This is the directory that the exe is downloaded to
$tempDirectory = "C:temp_provision"
# Installation Directory
# Some packages look for Python here
$targetDir = "C:Python36"
# Create the download directory and get the exe file
$pythonNameLoc = $tempDirectory + "python367.exe"
New-Item -ItemType directory -Path $tempDirectory -Force | Out-Null
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($pythonUrl, $pythonNameLoc)
# These are the silent arguments for the install of Python
# See https://docs.python.org/3/using/windows.html
$Arguments = @()
$Arguments += "/i"
$Arguments += 'InstallAllUsers="1"'
$Arguments += 'TargetDir="' + $targetDir + '"'
$Arguments += 'DefaultAllUsersTargetDir="' + $targetDir + '"'
$Arguments += 'AssociateFiles="1"'
$Arguments += 'PrependPath="1"'
$Arguments += 'Include_doc="1"'
$Arguments += 'Include_debug="1"'
$Arguments += 'Include_dev="1"'
$Arguments += 'Include_exe="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'InstallLauncherAllUsers="1"'
$Arguments += 'Include_lib="1"'
$Arguments += 'Include_pip="1"'
$Arguments += 'Include_symbols="1"'
$Arguments += 'Include_tcltk="1"'
$Arguments += 'Include_test="1"'
$Arguments += 'Include_tools="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += 'Include_launcher="1"'
$Arguments += "/passive"
# Install Python
Start-Process $pythonNameLoc -ArgumentList $Arguments -Wait
Function Get-EnvVariableNameList {
[cmdletbinding()]
$allEnvVars = Get-ChildItem Env:
$allEnvNamesArray = $allEnvVars.Name
$pathEnvNamesList = New-Object System.Collections.ArrayList
$pathEnvNamesList.AddRange($allEnvNamesArray)
return ,$pathEnvNamesList
}

Function Add-EnvVarIfNotPresent {
Param (
[string]$variableNameToAdd,
[string]$variableValueToAdd
)
$nameList = Get-EnvVariableNameList
$alreadyPresentCount = ($nameList | Where{$_ -like $variableNameToAdd}).Count
if ($alreadyPresentCount -eq 0)
{
[System.Environment]::SetEnvironmentVariable($variableNameToAdd, $variableValueToAdd, [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable($variableNameToAdd, $variableValueToAdd, [System.EnvironmentVariableTarget]::Process)
[System.Environment]::SetEnvironmentVariable($variableNameToAdd, $variableValueToAdd, [System.EnvironmentVariableTarget]::User)
$message = "Enviromental variable added to machine, process and user to include $variableNameToAdd"
}
else
{
$message = 'Environmental variable already exists. Consider using a different function to modify it'
}
Write-Information $message
}
Function Get-EnvExtensionList {
[cmdletbinding()]
$pathExtArray = ($env:PATHEXT).Split("{;}")
$pathExtList = New-Object System.Collections.ArrayList
$pathExtList.AddRange($pathExtArray)
return ,$pathExtList
}
Function Add-EnvExtension {
Param (
[string]$pathExtToAdd
)
$pathList = Get-EnvExtensionList
$alreadyPresentCount = ($pathList | Where{$_ -like $pathToAdd}).Count
if ($alreadyPresentCount -eq 0)
{
$pathList.Add($pathExtToAdd)
$returnPath = $pathList -join ";"
[System.Environment]::SetEnvironmentVariable('pathext', $returnPath, [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable('pathext', $returnPath, [System.EnvironmentVariableTarget]::Process)
[System.Environment]::SetEnvironmentVariable('pathext', $returnPath, [System.EnvironmentVariableTarget]::User)
$message = "Path extension added to machine, process and user paths to include $pathExtToAdd"
}
else
{
$message = 'Path extension already exists'
}
Write-Information $message
}
Function Get-EnvPathList {
[cmdletbinding()]
$pathArray = ($env:PATH).Split("{;}")
$pathList = New-Object System.Collections.ArrayList
$pathList.AddRange($pathArray)
return ,$pathList
}
Function Add-EnvPath {
Param (
[string]$pathToAdd
)
$pathList = Get-EnvPathList
$alreadyPresentCount = ($pathList | Where{$_ -like $pathToAdd}).Count
if ($alreadyPresentCount -eq 0)
{
$pathList.Add($pathToAdd)
$returnPath = $pathList -join ";"
[System.Environment]::SetEnvironmentVariable('path', $returnPath, [System.EnvironmentVariableTarget]::Machine)
[System.Environment]::SetEnvironmentVariable('path', $returnPath, [System.EnvironmentVariableTarget]::Process)
[System.Environment]::SetEnvironmentVariable('path', $returnPath, [System.EnvironmentVariableTarget]::User)
$message = "Path added to machine, process and user paths to include $pathToAdd"
}
else
{
$message = 'Path already exists'
}
Write-Information $message
}
Add-EnvExtension '.PY'
Add-EnvExtension '.PYW'
Add-EnvPath 'C:Python36'
# Install a library using Pip
python -m pip install numpy
# Set the version and download URL for Python
$version = "3.9.5"
$url = "https://www.python.org/ftp/python/$version/python-$version-amd64.exe"
# Download and install Python
$installPath = "$($env:ProgramFiles)Python$version"
Invoke-WebRequest $url -OutFile python-$version.exe
Start-Process python-$version.exe -ArgumentList "/quiet", "TargetDir=$installPath" -Wait
# Add Python to the system PATH
$envVariable = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($envVariable -notlike "*$installPath*") {
[Environment]::SetEnvironmentVariable("Path", "$envVariable;$installPath", "Machine")
Write-Host "Added Python to PATH."
}
# Clean up
Remove-Item python-$version.exe

这是我为Windows整理的东西,用于从endoflife.date/api检查最新的Python解释器版本。将其下载到您的 C: 驱动器上,并将 Python 可执行文件包含在用户的路径中:

@echo off
setlocal EnableDelayedExpansion
set url=https://endoflife.date/api/python.json
set "response="
for /f "usebackq delims=" %%i in (`powershell -command "& {(Invoke-WebRequest -Uri '%url%').Content}"`) do set "response=!response!%%i"
set "latest_py_version="
for /f "tokens=1,2 delims=}" %%a in ("%response%") do (
set "object=%%a}"
for %%x in (!object!) do (
for /f "tokens=1,* delims=:" %%y in ("%%x") do (
if "%%~y" == "latest" (
set "latest_py_version=%%~z"
)
)
)
)
echo %latest_py_version%
REM Set the minimum required Python version
set python_version=%latest_py_version%
REM Check if Python is already installed and if the version is less than python_version
echo Checking if Python %python_version% or greater is already installed...
set "current_version="
where python >nul 2>nul && (
for /f "tokens=2" %%v in ('python --version 2^>^&1') do set "current_version=%%v"
)
if "%current_version%"=="" (
echo Python is not installed. Proceeding with installation.
) else (
if "%current_version%" geq "%python_version%" (
echo Python %python_version% or greater is already installed. Exiting.
pause
exit
)
)
REM Define the URL and file name of the Python installer
set "url=https://www.python.org/ftp/python/%python_version%/python-%python_version%-amd64.exe"
set "installer=python-%python_version%-amd64.exe"
REM Define the installation directory
set "targetdir=C:Python%python_version%"
REM Download the Python installer
echo Downloading Python installer...
powershell -Command "(New-Object Net.WebClient).DownloadFile('%url%', '%installer%')"
REM Install Python with a spinner animation
echo Installing Python...
start /wait %installer% /quiet /passive TargetDir=%targetdir% Include_test=0 ^
&& (echo Done.) || (echo Failed!)
echo.
REM Add Python to the system PATH
echo Adding Python to the system PATH...
setx PATH "%targetdir%;%PATH%"
if %errorlevel% EQU 1 (
echo Python has been successfully installed to your system BUT failed to set system PATH. Try running the script as administrator.
pause
exit
)
echo Python %python_version% has been successfully installed and added to the system PATH.
REM Cleanup
echo Cleaning up...
del %installer%
echo Done!
pause

最新更新