在批处理脚本期间重新启动环境和脚本
Restart environment and script during batch script
我已经构建了一些 FFmpeg powershell 脚本供我和其他一些人使用,我正在尝试使设置和更新过程尽可能简单。最终目标是能够 运行 1 个安装 Chocolatey、FFmpeg、git 的批处理文件,克隆 github 存储库(用于更新),并编辑 Windows注册表将实际的 FFmpeg powershell 脚本/控制台程序添加到 Windows Explorer 上下文菜单。通过这种方式,我只需将包含所有内容的文件夹一次传递给他们,每当我更改项目或向项目添加内容时,我都可以告诉他们再次 运行 批处理文件,然后所有内容都是最新的。
但是我正在努力寻找一种方法来安装 Chocolatey,然后 git 和 Chocolatey,然后 运行 git 命令并执行单个 .bat 文件.据我所知,在安装 Chocolatey 之后,我需要完全重新启动 shell,然后才能安装 git,然后我必须再次重新启动 shell,然后才能使用 [=20] =] 命令。截至目前,大部分实际处理都是通过从 .bat 文件启动的 Powershell 脚本进行的,并且随着每一步的执行,我更新了一个 txt 文件,尝试重新启动批处理脚本,并阅读txt 文件从我离开的地方继续:
@echo off
echo Administrative permissions required. Detecting permissions...
echo.
net session >nul 2>&1
if %errorLevel% == 0 (
echo Success: Administrative permissions confirmed.
echo.
) else (
echo Failure: Current permissions inadequate.
PAUSE
exit
)
set relativePath=%~dp0
set relativePath=%relativePath:~0,-1%
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\CheckRequiredPackages.ps1" -relativePath "%relativePath%"
set /p step=<"%relativePath%\Setup\Step.txt"
if %step% == 1 (
(echo 2) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\GetChocolatey.ps1"
start "" "%relativePath%\RunMe.bat"
exit
)
if %step% == 2 (
(echo 3) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\GetRequiredPackages.ps1"
start "" "%relativePath%\RunMe.bat"
exit
)
if %step% == 3 (
(echo 0) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\Update.ps1" -relativePath "%relativePath%"
)
PAUSE
Exit
问题是在批处理脚本中使用 start
命令似乎不起作用,我猜是因为新进程是从处理 Chocolatey 安装的同一进程产生的,所以它没有算作实际重新启动 shell。有什么方法可以真正重新启动 shell 并以某种方式让批处理文件在没有用户干预的情况下重新启动?
确实,start
启动的进程继承了调用 进程的环境,而不是从注册表中读取可能更新的环境变量定义。
Chocolatey 带有批处理文件 RefreshEnv.cmd
(C:\ProgramData\chocolatey\bin\RefreshEnv.cmd
,但 C:\ProgramData\chocolatey\bin
应该在 %PATH%
中)专门用于避免必须启动用于环境更新生效的新独立会话。
因此,类似以下的方法可能有效:
:: Assumes that Chocolatey was just installed to the default location.
call "%ProgramData%\chocolatey\bin\RefreshEnv.cmd"
:: If Chocolatey was *previously* installed and its installation directory
:: has already been added to %Path%, the following will do:
:: call RefreshEnv.cmd
call "%relativePath%\RunMe.bat"
由于 Chocolatey 仅在您的脚本执行期间安装,因此其二进制文件文件夹尚未在 %Path%
中,您必须通过其 完整路径调用 RefreshEnv.cmd
,如上所示 - 假定默认安装目录。
现在展示如何使用 .NET 方法直接从 PowerShell 刷新 $env:Path
(%Path%
) 环境变量,这是一个实用的解决方案。
但是请注意,RefreshEnv.cmd
更全面,因为它重新加载 所有 环境变量定义,因此可能是新添加和修改的.
请注意,从 PowerShell 调用 RefreshEnv.cmd
不会 起作用,因为它随后会运行 process(这意味着它无法更新 calling 进程的环境)。
但是,Chocolatey 提供了一个 Update-SessionEnvironment
PowerShell 命令(别名为 refreshenv
),您可以在 Chocolatey 安装后立即使用该命令,如下所示:
# Import the module that defines Update-SessionEnvironment aka refreshenv
Import-Module "$env:ProgramData\Chocolatey\helpers\chocolateyProfile.psm1"
# Refresh all environment variables.
Update-SessionEnvironment # or: refreshenv
请参阅 了解更稳健的方法,该方法不依赖于默认安装位置的假设。
我不确定为什么一开始没有考虑重新加载路径环境变量,但这比使用中间文件重新启动脚本 4 次要合理得多。
首先,我将 99% 的繁重工作从 .bat 文件转移到 Powershell 脚本,因为我使用 Batch 的唯一原因是用户可以通过单击文件轻松 运行探索者。我无法让 RefreshEnv
工作,这是 Chocolatey 的一个功能,但是 运行 在每个新包之间进行此操作效果很好:
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
所以我现在有这样的东西,批处理脚本只是启动这个 Powershell 脚本:
Write-Host "Installing / updating required packages..."
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol =
[System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
choco install ffmpeg -y
choco install git -y
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
Write-Host "Deleting old files..."
Remove-Item -LiteralPath $relativePath -Force -Recurse
Start-Sleep 2
Write-Host "`nUpdating Files..."
git clone https://github.com/TheNimble1/FFmpegContextCommands.git $relativePath
安装 Chocolatey,刷新路径,安装 FFmpeg & Git,刷新路径,删除旧文件,然后克隆 git 以替换为新文件。
我已经构建了一些 FFmpeg powershell 脚本供我和其他一些人使用,我正在尝试使设置和更新过程尽可能简单。最终目标是能够 运行 1 个安装 Chocolatey、FFmpeg、git 的批处理文件,克隆 github 存储库(用于更新),并编辑 Windows注册表将实际的 FFmpeg powershell 脚本/控制台程序添加到 Windows Explorer 上下文菜单。通过这种方式,我只需将包含所有内容的文件夹一次传递给他们,每当我更改项目或向项目添加内容时,我都可以告诉他们再次 运行 批处理文件,然后所有内容都是最新的。
但是我正在努力寻找一种方法来安装 Chocolatey,然后 git 和 Chocolatey,然后 运行 git 命令并执行单个 .bat 文件.据我所知,在安装 Chocolatey 之后,我需要完全重新启动 shell,然后才能安装 git,然后我必须再次重新启动 shell,然后才能使用 [=20] =] 命令。截至目前,大部分实际处理都是通过从 .bat 文件启动的 Powershell 脚本进行的,并且随着每一步的执行,我更新了一个 txt 文件,尝试重新启动批处理脚本,并阅读txt 文件从我离开的地方继续:
@echo off
echo Administrative permissions required. Detecting permissions...
echo.
net session >nul 2>&1
if %errorLevel% == 0 (
echo Success: Administrative permissions confirmed.
echo.
) else (
echo Failure: Current permissions inadequate.
PAUSE
exit
)
set relativePath=%~dp0
set relativePath=%relativePath:~0,-1%
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\CheckRequiredPackages.ps1" -relativePath "%relativePath%"
set /p step=<"%relativePath%\Setup\Step.txt"
if %step% == 1 (
(echo 2) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\GetChocolatey.ps1"
start "" "%relativePath%\RunMe.bat"
exit
)
if %step% == 2 (
(echo 3) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\GetRequiredPackages.ps1"
start "" "%relativePath%\RunMe.bat"
exit
)
if %step% == 3 (
(echo 0) > "%relativePath%\Setup\Step.txt"
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%relativePath%\Setup\Update.ps1" -relativePath "%relativePath%"
)
PAUSE
Exit
问题是在批处理脚本中使用 start
命令似乎不起作用,我猜是因为新进程是从处理 Chocolatey 安装的同一进程产生的,所以它没有算作实际重新启动 shell。有什么方法可以真正重新启动 shell 并以某种方式让批处理文件在没有用户干预的情况下重新启动?
确实,start
启动的进程继承了调用 进程的环境,而不是从注册表中读取可能更新的环境变量定义。
Chocolatey 带有批处理文件 RefreshEnv.cmd
(C:\ProgramData\chocolatey\bin\RefreshEnv.cmd
,但 C:\ProgramData\chocolatey\bin
应该在 %PATH%
中)专门用于避免必须启动用于环境更新生效的新独立会话。
因此,类似以下的方法可能有效:
:: Assumes that Chocolatey was just installed to the default location.
call "%ProgramData%\chocolatey\bin\RefreshEnv.cmd"
:: If Chocolatey was *previously* installed and its installation directory
:: has already been added to %Path%, the following will do:
:: call RefreshEnv.cmd
call "%relativePath%\RunMe.bat"
由于 Chocolatey 仅在您的脚本执行期间安装,因此其二进制文件文件夹尚未在 %Path%
中,您必须通过其 完整路径调用 RefreshEnv.cmd
,如上所示 - 假定默认安装目录。
$env:Path
(%Path%
) 环境变量,这是一个实用的解决方案。
但是请注意,RefreshEnv.cmd
更全面,因为它重新加载 所有 环境变量定义,因此可能是新添加和修改的.
请注意,从 PowerShell 调用 RefreshEnv.cmd
不会 起作用,因为它随后会运行 process(这意味着它无法更新 calling 进程的环境)。
但是,Chocolatey 提供了一个 Update-SessionEnvironment
PowerShell 命令(别名为 refreshenv
),您可以在 Chocolatey 安装后立即使用该命令,如下所示:
# Import the module that defines Update-SessionEnvironment aka refreshenv
Import-Module "$env:ProgramData\Chocolatey\helpers\chocolateyProfile.psm1"
# Refresh all environment variables.
Update-SessionEnvironment # or: refreshenv
请参阅
我不确定为什么一开始没有考虑重新加载路径环境变量,但这比使用中间文件重新启动脚本 4 次要合理得多。
首先,我将 99% 的繁重工作从 .bat 文件转移到 Powershell 脚本,因为我使用 Batch 的唯一原因是用户可以通过单击文件轻松 运行探索者。我无法让 RefreshEnv
工作,这是 Chocolatey 的一个功能,但是 运行 在每个新包之间进行此操作效果很好:
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
所以我现在有这样的东西,批处理脚本只是启动这个 Powershell 脚本:
Write-Host "Installing / updating required packages..."
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol =
[System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
choco install ffmpeg -y
choco install git -y
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
Write-Host "Deleting old files..."
Remove-Item -LiteralPath $relativePath -Force -Recurse
Start-Sleep 2
Write-Host "`nUpdating Files..."
git clone https://github.com/TheNimble1/FFmpegContextCommands.git $relativePath
安装 Chocolatey,刷新路径,安装 FFmpeg & Git,刷新路径,删除旧文件,然后克隆 git 以替换为新文件。