如何在 Chocolatey 安装后刷新 PowerShell 会话的环境而无需打开新会话

How to refresh the environment of a PowerShell session after a Chocolatey install without needing to open a new session

我正在编写用于将 GitHub 源代码克隆到本地计算机的自动化脚本。
我在我的脚本中安装 Git 后失败了,它要求 close/open powershell.
所以我无法在安装 Git.

后自动克隆代码

这是我的代码:

iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
 choco install -y git
 refreshenv
 Start-Sleep -Seconds 15

 git clone --mirror https://${username}:${password}@$hostname/${username}/$Projectname.git D:\GitTemp -q 2>&1 | %{ "$_" } 

错误:

git : The term 'git' is not recognized as the name of a cmdlet, 
      function, script file, or operable program. 
      Check the spelling of the name, or if a path was included, 
      verify that the path is correct and try again.

请问我应该在不退出的情况下重新启动 PowerShell 吗?

您可以尝试使用 Update-SessionEnvironment:

Updates the environment variables of the current powershell session with any environment variable changes that may have occured during a Chocolatey package install.

这将测试该更改在巧克力调用后是否仍然有效。

如果没有,一个简单的解决方法是至少使用绝对路径调用 git

call Git from Powershell

new-item -path alias:git -value 'C:\Program Files\Git\bin\git.exe'

那你可以试试:

git clone --mirror https://${username}:${password}@$hostname/${username}/$Projectname.git D:\GitTemp -q 2>&1 | %{ "$_" } 

您遇到引导问题:

  • refreshenvUpdate-SessionEnvironment 的别名)是通常用于更新当前会话的正确命令choco install ... 命令后变量发生变化。

  • 但是,安装 Chocolatey 本身后立即refreshenv / Update-SessionEnvironment 本身仅在 以后可用 PowerShell 会话,因为加载这些命令是通过添加到配置文件 $PROFILE 的代码发生的,基于环境变量 $env:ChocolateyInstall

就是说,您应该能够 模拟 $PROFILE 在未来的会话中获取时 Chocolatey 所做的,以便能够使用 refreshenv / Update-SessionEnvironment 立即,安装 Chocolatey 后立即:

iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

choco install -y git

# Make `refreshenv` available right away, by defining the $env:ChocolateyInstall
# variable and importing the Chocolatey profile module.
# Note: Using `. $PROFILE` instead *may* work, but isn't guaranteed to.
$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."   
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"

# refreshenv is now an alias for Update-SessionEnvironment
# (rather than invoking refreshenv.cmd, the *batch file* for use with cmd.exe)
# This should make git.exe accessible via the refreshed $env:PATH, so that it
# can be called by name only.
refreshenv

# Verify that git can be called.
git --version

注意:原始解决方案使用 . $PROFILE 而不是 Import-Module ... 来加载 Chocolatey 配置文件,依赖于 Chocolatey 在那时已经更新 $PROFILE。但是,ferventcoder 指出 $PROFILE 的这种更新并不 总是 发生,因此不能依赖它。

我选择低技术解决方案:

$env:Path += ";C:\Program Files\Git\bin"

新:

我最初回答的旧方法对使用 ; 定界符的环境变量有一些怪癖。我尝试通过单独处理 PATH 来补偿,但有时还有其他此类变量。

所以这是新方法;您可能想将其放入脚本或其他内容中。它必须真正快速地嵌套几个 powershell 进程,这并不理想,但这是我发现逃离活动环境并捕获输出的唯一可靠方法。

# Call a powershell process to act as a wrapper to capture the output:
& ([Diagnostics.Process]::GetCurrentProcess().ProcessName) -NoP -c (
# String wrapper to help make the code more readable through comma-separation:
[String]::Join(' ', (
# Start a process that escapes the active environment:
'Start-Process', [Diagnostics.Process]::GetCurrentProcess().ProcessName,
'-UseNewEnvironment -NoNewWindow -Wait -Args ''-c'',',
# List the environment variables, separated by a tab character:
'''Get-ChildItem env: | &{process{ $_.Key + [char]9 + $_.Value }}'''
))) | &{process{
  # Set each line of output to a process-scoped environment variable:
  [Environment]::SetEnvironmentVariable(
    $_.Split("`t")[0], # Key
    $_.Split("`t")[1], # Value
    'Process'          # Scope
  )
}}

旧:

我尽了最大努力使它成为单行代码,但由于 PATH 变量需要特殊处理,所以我只能做一个愚蠢的长行。从好的方面来说,您不需要依赖任何第三方模块:

foreach ($s in 'Machine','User') {
  [Environment]::GetEnvironmentVariables($s).GetEnumerator().
  Where({$_.Key -ne 'PATH'}) | ForEach-Object {
    [Environment]::SetEnvironmentVariable($_.Key,$_.Value,'Process') }}

$env:PATH = ( ('Machine','User').ForEach({
  [Environment]::GetEnvironmentVariable('PATH',$_)}).
  Split(';').Where({$_}) | Select-Object -Unique ) -join ';'

代码的范围仅限于流程,因此您不必担心任何事情会搞砸(不是那样,我测试过)。


注意:这两种方法都不会删除在您的活动环境中创建的唯一命名的环境变量,因此如果您定义 $env:FOO = 'bar' 并且 'FOO' 通常不是您的环境之一变量,$env:FOO 仍将 return bar 即使上述任何代码为 运行.