在批处理脚本期间重新启动环境和脚本

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.cmdC:\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 以替换为新文件。