可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have found out that setting the PATH environment variable affects only the old command prompt. PowerShell seems to have different environment settings. How do I change the environment variables for PowerShell (v1)?
Note:
I want to make my changes permanent, so I don\'t have to set it every time I run PowerShell. Does PowerShell have a profile file? Something like Bash profile on Unix?
回答1:
Changing the actual environment variables can be done by
using the env: namespace / drive
information. For example, this
code will update the path environment variable:
$env:Path = \"SomeRandomPath\";
There are ways to make environment settings permanent, but
if you are only using them from PowerShell, it\'s probably
a lot better to use your profile to initiate the
settings. On startup, PowerShell will run any .ps1
files it finds in the WindowsPowerShell directory under
My Documents folder. Typically you have a profile.ps1
file already there. The path on my computer is
c:\\Users\\JaredPar\\Documents\\WindowsPowerShell\\profile.ps1
回答2:
If, some time during a PowerShell session, you need to
append to the PATH environment variable temporarily, you can
do it this way:
$env:Path += \";C:\\Program Files\\GnuWin32\\bin\"
回答3:
You can also modify user/system environment variables permanently (i.e. will be persistent across shell restarts) with the following:
### Modify a system environment variable ###
[Environment]::SetEnvironmentVariable
(\"Path\", $env:Path, [System.EnvironmentVariableTarget]::Machine)
### Modify a user environment variable ###
[Environment]::SetEnvironmentVariable
(\"INCLUDE\", $env:INCLUDE, [System.EnvironmentVariableTarget]::User)
### Usage from comments - add to the system environment variable ###
[Environment]::SetEnvironmentVariable(\"Path\", $env:Path + \";C:\\bin\", [EnvironmentVariableTarget]::Machine)
回答4:
From the PowerShell prompt:
setx PATH \"$env:path;\\the\\directory\\to\\add\" -m
You should then see the text:
SUCCESS: Specified value was saved.
Restart your session, and the variable will be available. setx
can also be used to set arbitrary variables. Type setx /?
at the prompt for documentation.
Before messing with your path in this way, make sure that you save a copy of your existing path by doing $env:path >> a.out
in a PowerShell prompt.
回答5:
Like JeanT\'s answer, I wanted an abstraction around adding to the path. Unlike JeanT\'s answer I needed it to run without user interaction. Other behavior I was looking for:
- Updates
$env:Path
so the change takes effect in the current session
- Persists the environment variable change for future sessions
- Doesn\'t add a duplicate path when the same path already exists
In case it\'s useful, here it is:
function Add-EnvPath {
param(
[Parameter(Mandatory=$true)]
[string] $Path,
[ValidateSet(\'Machine\', \'User\', \'Session\')]
[string] $Container = \'Session\'
)
if ($Container -ne \'Session\') {
$containerMapping = @{
Machine = [EnvironmentVariableTarget]::Machine
User = [EnvironmentVariableTarget]::User
}
$containerType = $containerMapping[$Container]
$persistedPaths = [Environment]::GetEnvironmentVariable(\'Path\', $containerType) -split \';\'
if ($persistedPaths -notcontains $Path) {
$persistedPaths = $persistedPaths + $Path | where { $_ }
[Environment]::SetEnvironmentVariable(\'Path\', $persistedPaths -join \';\', $containerType)
}
}
$envPaths = $env:Path -split \';\'
if ($envPaths -notcontains $Path) {
$envPaths = $envPaths + $Path | where { $_ }
$env:Path = $envPaths -join \';\'
}
}
Check out my gist for the corresponding Remove-EnvPath
function.
回答6:
Although the current accepted answer works in the sense that the path variable gets permanently updated from the context of PowerShell, it doesn\'t actually update the environment variable stored in the Windows registry.
To achieve that, you can obviously use PowerShell as well:
$oldPath=(Get-ItemProperty -Path \'Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\' -Name PATH).Path
$newPath=$oldPath+’;C:\\NewFolderToAddToTheList\\’
Set-ItemProperty -Path \'Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\' -Name PATH –Value $newPath
More information is in blog post Use PowerShell to Modify Your Environmental Path
If you use PowerShell community extensions, the proper command to add a path to the environment variable path is:
Add-PathVariable \"C:\\NewFolderToAddToTheList\" -Target Machine
回答7:
All the answers suggesting a permanent change have the same problem: They break the path registry value.
SetEnvironmentVariable
turns the REG_EXPAND_SZ
value %SystemRoot%\\system32
into a REG_SZ
value of C:\\Windows\\system32
.
Any other variables in the path are lost as well. Adding new ones using %myNewPath%
won\'t work any more.
Here\'s a script Set-PathVariable.ps1
that I use to address this problem:
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$NewLocation)
Begin
{
#requires –runasadministrator
$regPath = \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"
$hklm = [Microsoft.Win32.Registry]::LocalMachine
Function GetOldPath()
{
$regKey = $hklm.OpenSubKey($regPath, $FALSE)
$envpath = $regKey.GetValue(\"Path\", \"\", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
return $envPath
}
}
Process
{
# Win32API error codes
$ERROR_SUCCESS = 0
$ERROR_DUP_NAME = 34
$ERROR_INVALID_DATA = 13
$NewLocation = $NewLocation.Trim();
If ($NewLocation -eq \"\" -or $NewLocation -eq $null)
{
Exit $ERROR_INVALID_DATA
}
[string]$oldPath = GetOldPath
Write-Verbose \"Old Path: $oldPath\"
# Check whether the new location is already in the path
$parts = $oldPath.split(\";\")
If ($parts -contains $NewLocation)
{
Write-Warning \"The new location is already in the path\"
Exit $ERROR_DUP_NAME
}
# Build the new path, make sure we don\'t have double semicolons
$newPath = $oldPath + \";\" + $NewLocation
$newPath = $newPath -replace \";;\",\"\"
if ($pscmdlet.ShouldProcess(\"%Path%\", \"Add $NewLocation\")){
# Add to the current session
$env:path += \";$NewLocation\"
# Save into registry
$regKey = $hklm.OpenSubKey($regPath, $True)
$regKey.SetValue(\"Path\", $newPath, [Microsoft.Win32.RegistryValueKind]::ExpandString)
Write-Output \"The operation completed successfully.\"
}
Exit $ERROR_SUCCESS
}
I explain the problem in more detail in a blog post.
回答8:
This sets the path for the current session and prompts the user to add it permanently:
function Set-Path {
param([string]$x)
$Env:Path+= \";\" + $x
Write-Output $Env:Path
$write = Read-Host \'Set PATH permanently ? (yes|no)\'
if ($write -eq \"yes\")
{
[Environment]::SetEnvironmentVariable(\"Path\",$env:Path, [System.EnvironmentVariableTarget]::User)
Write-Output \'PATH updated\'
}
}
You can add this function to your default profile, (Microsoft.PowerShell_profile.ps1
), usually located at %USERPROFILE%\\Documents\\WindowsPowerShell
.
回答9:
As Jonathan Leaders mentioned here, it is important to run the command/script elevated to be able to change environment variables for \'machine\', but running some commands elevated doesn\'t have to be done with the Community Extensions, so I\'d like to modify and extend JeanT\'s answer in a way, that changing machine variables also can be performed even if the script itself isn\'t run elevated:
function Set-Path ([string]$newPath, [bool]$permanent=$false, [bool]$forMachine=$false )
{
$Env:Path += \";$newPath\"
$scope = if ($forMachine) { \'Machine\' } else { \'User\' }
if ($permanent)
{
$command = \"[Environment]::SetEnvironmentVariable(\'PATH\', $env:Path, $scope)\"
Start-Process -FilePath powershell.exe -ArgumentList \"-noprofile -command $Command\" -Verb runas
}
}
回答10:
Most answers aren\'t addressing UAC. This covers UAC issues.
First install PowerShell Community Extensions: choco install pscx
via http://chocolatey.org/ (you may have to restart your shell environment).
Then enable pscx
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser #allows scripts to run from the interwebs, such as pcsx
Then use Invoke-Elevated
Invoke-Elevated {Add-PathVariable $args[0] -Target Machine} -ArgumentList $MY_NEW_DIR
回答11:
Building on @Michael Kropat\'s answer I added a parameter to prepend the new path to the existing PATH
variable and a check to avoid the addition of a non-existing path:
function Add-EnvPath {
param(
[Parameter(Mandatory=$true)]
[string] $Path,
[ValidateSet(\'Machine\', \'User\', \'Session\')]
[string] $Container = \'Session\',
[Parameter(Mandatory=$False)]
[Switch] $Prepend
)
if (Test-Path -path \"$Path\") {
if ($Container -ne \'Session\') {
$containerMapping = @{
Machine = [EnvironmentVariableTarget]::Machine
User = [EnvironmentVariableTarget]::User
}
$containerType = $containerMapping[$Container]
$persistedPaths = [Environment]::GetEnvironmentVariable(\'Path\', $containerType) -split \';\'
if ($persistedPaths -notcontains $Path) {
if ($Prepend) {
$persistedPaths = ,$Path + $persistedPaths | where { $_ }
[Environment]::SetEnvironmentVariable(\'Path\', $persistedPaths -join \';\', $containerType)
}
else {
$persistedPaths = $persistedPaths + $Path | where { $_ }
[Environment]::SetEnvironmentVariable(\'Path\', $persistedPaths -join \';\', $containerType)
}
}
}
$envPaths = $env:Path -split \';\'
if ($envPaths -notcontains $Path) {
if ($Prepend) {
$envPaths = ,$Path + $envPaths | where { $_ }
$env:Path = $envPaths -join \';\'
}
else {
$envPaths = $envPaths + $Path | where { $_ }
$env:Path = $envPaths -join \';\'
}
}
}
}
回答12:
MY SUGGESTION IS THIS ONE
i HAVE TESTED THIS TO ADD C:\\oracle\\x64\\bin to Path permanently and this works fine.
$ENV:PATH
The first way is simply to do:
$ENV:PATH=”$ENV:PATH;c:\\path\\to\\folder”
But this change isn’t permenantly, $env:path will default back to what it was before as soon as you close your powershell terminal and reopen it again. That’s because you have applied the change at the session level and not at the source level (which is the registry level). To view the global value of $env:path, do:
Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment’ -Name PATH
or, more specifically:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment’ -Name PATH).path
Now to change this, first we capture the original path that needs to be modified:
$oldpath = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment’ -Name PATH).path
Now we define what the new path should look like, in this case we are appending a new folder:
$newpath = “$oldpath;c:\\path\\to\\folder”
Note: Be sure that the $newpath looks how you want it to look, if not then you could damage your OS.
Now apply the new value:
Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment’ -Name PATH -Value $newPath
Now do one final check that it looks how you expect it:
(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment’ -Name PATH).Path
You can now restart your powershell terminal (or even reboot machine) and see that it doesn’t rollback to it’s old value again. Note the ordering of the paths may change so that it’s in alphabetical order, so make sure you check the whole line, to make it easier, you can split the output into rows by using the semi-colon as a delimeter:
($env:path).split(“;”)