41

これは簡単な質問かもしれませんが、適切な答えを見つけることができませんでした。

現在のWindowsPowerShellセッションを閉じずに、現在のWindows PowerShellセッション内から環境変数を更新するにはどうすればよいですか?

これまで、たとえば[コントロールパネル]> [システム]PATHから環境変数を変更する場合、変数を更新するために現在のセッションを閉じて新しいセッションを開く必要があります。そうしないと、面倒な問題が発生します。SetEnviromentVariable

私はLinuxの世界から来ているので、sourceコマンドのようなものを探しています。

4

6 に答える 6

36

このようなもののためにレジストリでゴミ箱に飛び込む必要はありません:

foreach($level in "Machine","User") {
   [Environment]::GetEnvironmentVariables($level)
}

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)" }
}

Set-Contentは、次のようなことを行うのと同じように、実際にプロセス環境で変数を設定することに注意してください。$env:Temp = Convert-Path ~\AppData\Local\Temp

于 2014-03-26T19:11:16.250 に答える
15

プロセスの起動時に環境にデータが入力されるため、プロセスを再起動する必要があります。

レジストリから環境を読み取ることにより、環境を更新できます。たぶん、次のようなスクリプトを使用します。

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
    }
}

(未テスト)

于 2013-01-17T15:09:55.250 に答える
14

これは古い質問ですが、chocolateyrefreshenvを使用すると、便利なコマンドもインストールされます。これは私にとっては問題なく機能します。

于 2017-01-18T09:16:20.977 に答える
11

現在のPowerShellセッションのパスのみを更新する場合は、次のようにします。

$env:Path += ";<new path>"

PATH env変数を更新して、新しいPowerShellセッション間で永続化する必要がある場合は、次を使用します。

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

すべてのユーザーのパスを変更する場合は、「ユーザー」を「マシン」に変更します。

于 2013-01-17T16:03:11.327 に答える
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
        }
    }
}
于 2013-01-29T18:26:16.610 に答える
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}"
}

これはほとんどテストされていないことに注意してください。ただし、原則は健全であり、この分野で過去に行った作業に基づいています。

于 2014-03-26T21:20:48.303 に答える