我为我和其他一些人构建了一些FFmpeg powershell脚本,并且我试图使设置和更新过程尽可能地容易。最终目标是能够运行1个批处理文件,该批文件安装Chocolatey,FFmpeg,git,克隆github存储库(以进行更新),并编辑Windows注册表以将实际的FFmpeg powershell脚本/控制台程序添加到Windows资源管理器上下文菜单中。这样,我只要将包含所有内容的文件夹传递给他们,就可以在每次更改或向项目中添加内容时告诉它们再次运行批处理文件,并保存所有内容为最新。
但是我正在努力寻找一种方法来安装Chocolatey,然后使用Chocolatey进行git,然后在执行单个.bat文件的情况下运行git命令。从安装Chocolatey之后我可以看到的信息,我需要完全重新启动外壳,然后才能安装git,然后必须再次重新启动外壳,然后才能使用git命令。到目前为止,大多数实际处理都是通过从.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安装的同一进程中产生的,因此不算是实际重新启动贝壳。有没有什么方法可以真正地重新启动外壳程序,并且以某种方式可以在没有用户干预的情况下启动批处理文件?
[我不确定为什么我最初不打算重新加载路径环境变量,但这比使用中间文件重新启动脚本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以替换为新文件。
实际上,start
启动的进程继承了calling进程的环境,而不是从注册表中读取可能更新的环境变量定义。
巧克力与批处理文件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
,如上所示-假定默认安装目录。[Your own answer现在显示了如何直接从_from PowerShell使用.NET方法刷新$env:Path
(%Path%
)环境变量,这是一个务实的解决方案。
但是,请注意,RefreshEnv.cmd
是更全面的,因为它重新加载了[[all
RefreshEnv.cmd
从PowerShell会执行非
,因为它随后运行进程外(这意味着它无法更新calling进程的环境”) 。但是,巧克力提供了Update-SessionEnvironment
PowerShell命令(别名为refreshenv
)
# 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
请参见this answer,这是一种更强大的方法,它不依赖于假定默认位置已安装到的位置。