如何从注册表更新Windows PowerShell会话环境变量?

Pab*_*gos 33 powershell

这可能是一个简单的问题,但我找不到合适的答案.

如何在不关闭当前Windows PowerShell会话的情况下从当前Windows PowerShell会话中更新环境变量?

到目前为止,当我PATH控制面板>系统修改环境变量时,我必须关闭当前会话并打开一个新会话,以便刷新变量或发出SetEnviromentVariable繁琐的变量.

我来自Linux世界,所以我正在寻找像source命令这样的东西.

Jay*_*kul 29

这个东西没有必要在注册表中使用dumpster潜水:

foreach($level in "Machine","User") {
   [Environment]::GetEnvironmentVariables($level)
}
Run Code Online (Sandbox Code Playgroud)

如果你想让PATH变量正常工作,你必须特别对待它们(也就是说,将(可能的)新东西连接到你已经拥有的东西上,而不是丢失任何东西,因为你无法确定你是什么应该删除).

foreach($level in "Machine","User") {
   [Environment]::GetEnvironmentVariables($level).GetEnumerator() | % {
      # For Path variables, append the new values, if they're not already in there
      if($_.Name -match 'Path$') { 
         $_.Value = ($((Get-Content "Env:$($_.Name)") + ";$($_.Value)") -split ';' | Select -unique) -join ';'
      }
      $_
   } | Set-Content -Path { "Env:$($_.Name)" }
}
Run Code Online (Sandbox Code Playgroud)

请注意,Set-Content实际上在您的流程环境中设置变量,就像执行类似操作一样$env:Temp = Convert-Path ~\AppData\Local\Temp

  • 库存注意事项Windows 7:Set-Content管道似乎无法在PowerShell v2.0上正常运行.我必须长手,`| ForEach {Set-Content -Path"Env:$($ _.Name)" - Value $ _.Value}` (2认同)

Joe*_*oey 12

在进程启动时会填充环境,这就是您需要重新启动进程的原因.

您可以通过从注册表中读取环境来更新环境.也许使用如下脚本:

function Update-Environment {
    $locations = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
                 'HKCU:\Environment'

    $locations | ForEach-Object {
        $k = Get-Item $_
        $k.GetValueNames() | ForEach-Object {
            $name  = $_
            $value = $k.GetValue($_)

            if ($userLocation -and $name -ieq 'PATH') {
                Env:\Path += ";$value"
            } else {
                Set-Item -Path Env:\$name -Value $value
            }
        }

        $userLocation = $true
    }
}
Run Code Online (Sandbox Code Playgroud)

(另)


Eam*_*nne 11

这是一个老问题,但如果你使用chocolatey,它还会安装方便的refreshenv命令,这对我来说很好.

  • `refreshenv`似乎刷新`cmd`会话但不是PowerShell. (7认同)

Kei*_*ill 6

如果只想更新当前PowerShell会话的路径,请执行以下操作:

$env:Path += ";<new path>"
Run Code Online (Sandbox Code Playgroud)

如果需要更新PATH env变量以使其在新的PowerShell会话中保持持久性,请使用:

[Environment]::SetEnvironmentVariable("PATH", $env:Path + ";<new path>", 'User')
Run Code Online (Sandbox Code Playgroud)

如果要更改所有用户的路径,请将"用户"更改为"计算机".

  • 我更理解这个问题»我更改了一个环境变量(来自GUI),但希望更改出现在已有的PowerShell会话中,而不必重新启动它.« (3认同)

Pab*_*gos 5

谢谢你@Joey的答案(我标记正确:))请注意,鉴于我想在那一刻根据注册表刷新所有变量,我摆脱了if-else子句......

我仔细检查了注册表变量的位置,并根据存储在注册表中的环境变量的位置是否正常

使用的代码段只是为了完整性....

function Update-Environment {   
    $locations = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
                 'HKCU:\Environment'

    $locations | ForEach-Object {   
        $k = Get-Item $_
        $k.GetValueNames() | ForEach-Object {
            $name  = $_
            $value = $k.GetValue($_)
            Set-Item -Path Env:\$name -Value $value
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Kir*_*nro 5

不幸的是,其他答案缺少一些重要细节.PSModulePath在PowerShell中有一些特殊处理,在更新环境变量时需要考虑这些处理.此外,可以添加,修改或删除变量.您需要考虑路径环境变量.

更糟糕的是,根据您执行此操作时所使用的产品/主机,该产品可能会有一些特殊的环境变量处理,除了希望Path环境变量(包含多个值) ,分号分隔)实际上包含"路径"作为其名称的一部分,你可能会错过某些东西(除非当然这是Windows如何在内部处理这些环境变量,这可能是,我没有挖到那么远的地方兔子洞).

这是我提出的一个脚本,我认为你可以在当前的PowerShell会话中正确更新环境变量,而无需重新启动它:

# Get all environment variables for the current Process, as well as System and User environment variable values
$processValues = [Environment]::GetEnvironmentVariables('Process')
$machineValues = [Environment]::GetEnvironmentVariables('Machine')
$userValues    = [Environment]::GetEnvironmentVariables('User')
# Identify the entire list of environment variable names first
$envVarNames = ($machineValues.Keys + $userValues.Keys + 'PSModulePath') | Sort-Object | Select-Object -Unique
# Now process all of those keys, updating what exists and adding what is new
foreach ($envVarName in $envVarNames) {
    if ($envVarName -eq 'PSModulePath') {
        $pieces = @()
        if ($PSVersionTable.PSVersion -ge [System.Version]'4.0') {
            $pieces += Join-Path -Path ${env:ProgramFiles} -ChildPath 'WindowsPowerShell\Modules'
        }
        if (-not $userValues.ContainsKey($envVarName)) {
            $pieces += Join-Path -Path ([Environment]::GetFolderPath('Documents')) -ChildPath 'WindowsPowerShell\Modules'
        } else {
            $pieces += $userValues[$envVarName] -split ';'
        }
        if ($machineValues.ContainsKey($envVarName)) {
            $pieces += $machineValues[$envVarName] -split ';'
        }
        [Environment]::SetEnvironmentVariable($envVarName,($pieces -join ';'),'Process')
    } elseif ($envVarName -match 'path') {
        $pieces = @()
        if ($userValues.ContainsKey($envVarName)) {
            $pieces += $userValues[$envVarName] -split ';'
        }
        if ($machineValues.ContainsKey($envVarName)) {
            $pieces += $machineValues[$envVarName] -split ';'
        }
        [Environment]::SetEnvironmentVariable($envVarName,($pieces -join ';'),'Process')
    } elseif ($userValues.ContainsKey($envVarName)) {
        [Environment]::SetEnvironmentVariable($envVarName,$userValue[$envVarName],'Process')
    } elseif ($machineValues.ContainsKey($envVarName)) {
        [Environment]::SetEnvironmentVariable($envVarName,$machineValue[$envVarName],'Process')
    }
}
# Lastly remove the environment variables that no longer exist
foreach ($envVarName in $processValues.Keys | Where-Object {$envVarNames -notcontains $_}) {
    Remove-Item -LiteralPath "env:${envVarName}"
}
Run Code Online (Sandbox Code Playgroud)

请注意,这在很大程度上未经测试,但原则是合理的,并且它基于我过去在该领域所做的工作.