Is there a command to refresh environment variables from the command prompt in Windows?
如果修改或添加环境变量,则必须重新启动命令提示符。 我是否可以执行一个无需重启CMD即可执行的命令?
您可以使用vbs脚本捕获系统环境变量,但实际上需要一个bat脚本来更改当前环境变量,因此这是一个组合解决方案。
创建一个包含此代码的名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Set oShell = WScript.CreateObject("WScript.Shell") filename = oShell.ExpandEnvironmentStrings("%TEMP% esetvars.bat") Set objFileSystem = CreateObject("Scripting.fileSystemObject") Set oFile = objFileSystem.CreateTextFile(filename, TRUE) set oEnv=oShell.Environment("System") for each sitem in oEnv oFile.WriteLine("SET" & sitem) next path = oEnv("PATH") set oEnv=oShell.Environment("User") for each sitem in oEnv oFile.WriteLine("SET" & sitem) next path = path &";" & oEnv("PATH") oFile.WriteLine("SET PATH=" & path) oFile.Close |
创建另一个包含以下代码的文件resetvars.bat,位置相同:
1 2 3 4 | @echo off %~dp0resetvars.vbs call"%TEMP% esetvars.bat" |
当您要刷新环境变量时,只需运行
道歉:
我提出此解决方案的两个主要问题是
一种。我找不到将vbs脚本中的环境变量导出回命令提示符的简单方法,并且
b。 PATH环境变量是用户和系统PATH变量的串联。
我不确定用户和系统之间的变量冲突的一般规则是什么,因此我选择使用户覆盖系统,但专门处理的PATH变量除外。
我使用奇怪的vbs + bat + tempor bat机制来解决从vbs导出变量的问题。
注意:此脚本不会删除变量。
这可能可以改善。
添加
如果需要将环境从一个cmd窗口导出到另一个cmd窗口,请使用以下脚本(我们将其称为
1 2 3 4 5 6 7 8 9 10 11 | Set oShell = WScript.CreateObject("WScript.Shell") filename = oShell.ExpandEnvironmentStrings("%TEMP% esetvars.bat") Set objFileSystem = CreateObject("Scripting.fileSystemObject") Set oFile = objFileSystem.CreateTextFile(filename, TRUE) set oEnv=oShell.Environment("Process") for each sitem in oEnv oFile.WriteLine("SET" & sitem) next oFile.Close |
在要导出的窗口中运行
1 2 | "%TEMP% esetvars.bat" |
这是Chocolatey的用途。
https://github.com/chocolatey/choco/blob/master/src/chocolatey.resources/redirects/RefreshEnv.cmd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | @echo off :: :: RefreshEnv.cmd :: :: Batch file to read environment variables from registry and :: set session variables to these values. :: :: With this batch file, there should be no need to reload command :: environment every time you want environment changes to propagate echo | set /p dummy="Reading environment variables from registry. Please wait..." goto main :: Set one environment variable from registry key :SetFromReg "%WinDir%\System32 eg" QUERY"%~1" /v"%~2">"%TEMP%\_envset.tmp" 2>NUL for /f"usebackq skip=2 tokens=2,*" %%A IN ("%TEMP%\_envset.tmp") do ( echo/set %~3=%%B ) goto :EOF :: Get a list of environment variables from registry :GetRegEnv "%WinDir%\System32 eg" QUERY"%~1">"%TEMP%\_envget.tmp" for /f"usebackq skip=2" %%A IN ("%TEMP%\_envget.tmp") do ( if /I not"%%~A"=="Path" ( call :SetFromReg"%~1""%%~A""%%~A" ) ) goto :EOF :main echo/@echo off >"%TEMP%\_env.cmd" :: Slowly generating final file call :GetRegEnv"HKLM\System\CurrentControlSet\Control\Session Manager\Environment">>"%TEMP%\_env.cmd" call :GetRegEnv"HKCU\Environment">>"%TEMP%\_env.cmd">>"%TEMP%\_env.cmd" :: Special handling for PATH - mix both User and System call :SetFromReg"HKLM\System\CurrentControlSet\Control\Session Manager\Environment" Path Path_HKLM >>"%TEMP%\_env.cmd" call :SetFromReg"HKCU\Environment" Path Path_HKCU >>"%TEMP%\_env.cmd" :: Caution: do not insert space-chars before >> redirection sign echo/set Path=%%Path_HKLM%%;%%Path_HKCU%% >>"%TEMP%\_env.cmd" :: Cleanup del /f /q"%TEMP%\_envset.tmp" 2>nul del /f /q"%TEMP%\_envget.tmp" 2>nul :: Set these variables call"%TEMP%\_env.cmd" echo | set /p dummy="Done" echo . |
在Windows 7/8/10上,您可以安装Chocolatey,它具有内置的脚本。
安装Chocolatey之后,只需键入" refreshenv"而不带引号。
通过设计,Windows没有内置的机制可以将环境变量添加/更改/删除传播到已经运行的cmd.exe,可以从另一个cmd.exe或从"我的电脑->属性->高级设置->环境变量"。
如果在现有打开的命令提示符范围之外修改或添加新的环境变量,则需要重新启动命令提示符,或者在现有命令提示符下使用SET手动添加。
最新接受的答案显示了部分解决方法,方法是手动刷新脚本中的所有环境变量。该脚本处理在"我的电脑...环境变量"中全局更改环境变量的用例,但是如果在一个cmd.exe中更改了环境变量,该脚本将不会将其传播到另一个正在运行的cmd.exe。
在最终找到更简单的解决方案之前,我遇到了这个答案。
只需在任务管理器中重新启动
我没有测试,但是您可能还需要重新打开命令提示符。
感谢Timo Huovinen在这里:尽管成功安装了节点,但无法识别(如果这对您有帮助,请感谢此人的评论)。
在Windows 7上有效:
通过输入echo%PATH%进行测试,效果很好。如果您打开新的cmd,也可以设置,不再需要烦人的重启:)
使用" setx"并重新启动cmd提示符
有一个名为" setx"的命令行工具可用于此作业。
它用于读取和写入环境变量。
关闭命令窗口后,变量仍然存在。
它"无需编程或编写脚本即可在用户或系统环境中创建或修改环境变量。setx命令还检索注册表项的值并将其写入文本文件。"
注意:此工具创建或修改的变量将在以后的命令窗口中可用,但在当前的CMD.exe命令窗口中不可用。因此,您必须重新启动。
如果缺少
- http://download.microsoft.com/download/win2000platform/setx/1.00.0.1/nt5/en-us/setx_setup.exe
或修改注册表
MSDN说:
To programmatically add or modify system environment variables, add
them to the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
Manager\Environment registry key, then broadcast a WM_SETTINGCHANGE
message with lParam set to the string"Environment".This allows applications, such as the shell, to pick up your updates.
调用此功能对我有用:
1 2 3 4 5 | VOID Win32ForceSettingsChange() { DWORD dwReturnValue; ::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue); } |
我想到的最好的方法是只执行一个注册表查询。这是我的例子。
在我的示例中,我使用添加了新环境变量的批处理文件进行了安装。安装完成后,我需要立即执行此操作,但是无法使用这些新变量生成新进程。我测试了生成另一个浏览器窗口并调用cmd.exe的方法,该方法可以正常工作,但在Vista和Windows 7上,资源管理器仅作为单个实例运行,并且通常以登录用户身份运行。由于我需要管理员权限才能自动执行操作,因此失败无论从本地系统运行还是以管理员身份运行,都可以执行此操作。这样做的局限性在于它不能处理路径之类的问题,只能用于简单的环境变量。这使我可以使用批处理转到目录(包含空格)并复制运行.exes等文件。这是今天从stackoverflow.com上的may资源编写的
对新批次的原始批次调用:
testenvget.cmd SDROOT(或任何变量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @ECHO OFF setlocal ENABLEEXTENSIONS set keyname=HKLM\System\CurrentControlSet\Control\Session Manager\Environment set value=%1 SET ERRKEY=0 REG QUERY"%KEYNAME%" /v"%VALUE%" 2>NUL| FIND /I"%VALUE%" IF %ERRORLEVEL% EQU 0 ( ECHO The Registry Key Exists ) ELSE ( SET ERRKEY=1 Echo The Registry Key Does not Exist ) Echo %ERRKEY% IF %ERRKEY% EQU 1 GOTO :ERROR FOR /F"tokens=1-7" %%A IN ('REG QUERY"%KEYNAME%" /v"%VALUE%" 2^>NUL^| FIND /I"%VALUE%"') DO ( ECHO %%A ECHO %%B ECHO %%C ECHO %%D ECHO %%E ECHO %%F ECHO %%G SET ValueName=%%A SET ValueType=%%B SET C1=%%C SET C2=%%D SET C3=%%E SET C4=%%F SET C5=%%G ) SET VALUE1=%C1% %C2% %C3% %C4% %C5% echo The Value of %VALUE% is %C1% %C2% %C3% %C4% %C5% cd /d"%VALUE1%" pause REM **RUN Extra Commands here** GOTO :EOF :ERROR Echo The the Enviroment Variable does not exist. pause GOTO :EOF |
我还从各种不同的想法中想到了另一种方法。请看下面。基本上,这将从注册表中获取最新的路径变量,但是,这将导致许多问题,因为注册表查询本身将提供变量,这意味着到处都有变量将不起作用,因此请解决这个问题基本上使路径加倍。真讨厌比较合适的方法是:
设置路径=%Path%; C: Program Files Software ....
无论这是新的批处理文件,请谨慎使用。
1 2 3 4 5 6 7 8 | @ECHO OFF SETLOCAL ENABLEEXTENSIONS set org=%PATH% for /f"tokens=2*" %%A in ('REG QUERY"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path ^|FIND /I"Path"') DO ( SET path=%%B ) SET PATH=%org%;%PATH% set path |
为此,可以通过覆盖指定进程本身中的环境表来实现。
作为概念证明,我编写了此示例应用程序,该应用程序仅在cmd.exe进程中编辑了一个(已知)环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | typedef DWORD (__stdcall *NtQueryInformationProcessPtr)(HANDLE, DWORD, PVOID, ULONG, PULONG); int __cdecl main(int argc, char* argv[]) { HMODULE hNtDll = GetModuleHandleA("ntdll.dll"); NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll,"NtQueryInformationProcess"); int processId = atoi(argv[1]); printf("Target PID: %u ", processId); // open the process with read+write access HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, processId); if(hProcess == NULL) { printf("Error opening process (%u) ", GetLastError()); return 0; } // find the location of the PEB PROCESS_BASIC_INFORMATION pbi = {0}; NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); if(status != 0) { printf("Error ProcessBasicInformation (0x%8X) ", status); } printf("PEB: %p ", pbi.PebBaseAddress); // find the process parameters char *processParamsOffset = (char*)pbi.PebBaseAddress + 0x20; // hard coded offset for x64 apps char *processParameters = NULL; if(ReadProcessMemory(hProcess, processParamsOffset, &processParameters, sizeof(processParameters), NULL)) { printf("UserProcessParameters: %p ", processParameters); } else { printf("Error ReadProcessMemory (%u) ", GetLastError()); } // find the address to the environment table char *environmentOffset = processParameters + 0x80; // hard coded offset for x64 apps char *environment = NULL; ReadProcessMemory(hProcess, environmentOffset, &environment, sizeof(environment), NULL); printf("environment: %p ", environment); // copy the environment table into our own memory for scanning wchar_t *localEnvBlock = new wchar_t[64*1024]; ReadProcessMemory(hProcess, environment, localEnvBlock, sizeof(wchar_t)*64*1024, NULL); // find the variable to edit wchar_t *found = NULL; wchar_t *varOffset = localEnvBlock; while(varOffset < localEnvBlock + 64*1024) { if(varOffset[0] == '\0') { // we reached the end break; } if(wcsncmp(varOffset, L"ENVTEST=", 8) == 0) { found = varOffset; break; } varOffset += wcslen(varOffset)+1; } // check to see if we found one if(found) { size_t offset = (found - localEnvBlock) * sizeof(wchar_t); printf("Offset: %Iu ", offset); // write a new version (if the size of the value changes then we have to rewrite the entire block) if(!WriteProcessMemory(hProcess, environment + offset, L"ENVTEST=def", 12*sizeof(wchar_t), NULL)) { printf("Error WriteProcessMemory (%u) ", GetLastError()); } } // cleanup delete[] localEnvBlock; CloseHandle(hProcess); return 0; } |
样本输出:
1 2 3 4 5 6 7 8 9 10 11 | >set ENVTEST=abc >cppTest.exe 13796 Target PID: 13796 PEB: 000007FFFFFD3000 UserProcessParameters: 00000000004B2F30 environment: 000000000052E700 Offset: 1528 >set ENVTEST ENVTEST=def |
笔记
这种方法也将限于安全性限制。如果目标在更高的高度或更高的帐户(例如SYSTEM)下运行,则我们将无权编辑其内存。
如果要对32位应用程序执行此操作,则上面的硬编码偏移将分别更改为0x10和0x48。可以通过在调试器中转储_PEB和_RTL_USER_PROCESS_PARAMETERS结构来找到这些偏移量(例如在WinDbg
要将概念验证更改为OP所需的内容,它将只枚举当前系统和用户环境变量(如@tsadok的答案所记录),并将整个环境表写入目标进程的内存中。
编辑:环境块的大小也存储在_RTL_USER_PROCESS_PARAMETERS结构中,但是内存是在进程的堆上分配的。因此,从外部过程中,我们将无法调整大小并使其变大。我尝试使用VirtualAllocEx在目标进程中为环境存储分配额外的内存,并且能够设置和读取一个全新的表。不幸的是,任何以常规方式修改环境的尝试都将崩溃并烧毁,因为该地址不再指向堆(它将在RtlSizeHeap中崩溃)。
环境变量保存在HKEY_LOCAL_MACHINE SYSTEM ControlSet Control Session Manager Environment中。
许多有用的环境变量,例如Path,都存储为REG_SZ。有几种访问注册表的方法,包括REGEDIT:
输出以幻数开头。因此,要使用find命令搜索它,需要将其键入并重定向:
因此,如果您只想使用系统属性中的内容刷新当前命令会话中的path变量,则以下批处理脚本可以正常工作:
RefreshPath.cmd:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @echo off REM This solution requests elevation in order to read from the registry. if exist %temp%\env.reg del %temp%\env.reg /q /f REGEDIT /E %temp%\env.reg"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment" if not exist %temp%\env.reg ( echo"Unable to write registry to temp location" exit 1 ) SETLOCAL EnableDelayedExpansion for /f"tokens=1,2* delims==" %%i in ('type %temp%\env.reg ^| findstr -c:"Path"=') do ( set upath=%%~j echo !upath:\\=\! >%temp% ewpath ) ENDLOCAL for /f"tokens=*" %%i in (%temp% ewpath) do set path=%%i |
尝试以管理员身份打开新的命令提示符。这在Windows 10上对我有用。(我知道这是个老答案,但是我不得不分享这个,因为仅为此写一个VBS脚本是荒谬的)。
令人困惑的事情可能是有几个地方可以开始cmd。
以我为例,我从Windows资源管理器中运行了cmd,而从"运行"(Windows键+ r)启动cmd时,环境变量没有更改。
就我而言,我只需要从任务管理器中终止Windows资源管理器进程,然后再从任务管理器中重新启动它即可。
完成此操作后,我可以从Windows资源管理器中生成的cmd中访问新的环境变量。
在当前会话中不重新启动变量的情况下,将变量添加到路径的最简单方法是打开命令提示符并键入:
1 | PATH=(VARIABLE);%path% |
然后按enter。
检查您的变量是否已加载,键入
1 | PATH |
然后按enter。但是,在重新启动之前,变量将仅是路径的一部分。
重新启动资源管理器为我完成了此操作,但仅适用于新的cmd终端。
我设置路径的终端可能已经看到了新的Path变量(在Windows 7中)。
1 | taskkill /f /im explorer.exe && explorer.exe |
只需重新启动explorer.exe >>在Win 8 X64上测试
我在批处理脚本中使用以下代码:
1 2 3 4 5 | if not defined MY_ENV_VAR ( setx MY_ENV_VAR"VALUE"> nul set MY_ENV_VAR=VALUE ) echo %MY_ENV_VAR% |
通过在SETX之后使用SET,可以直接使用"本地"变量,而无需重新启动命令窗口。在下一次运行时,将使用环境变量。
我喜欢在匿名co夫的答案中贴上的巧克力味方法,因为它是纯批处理方法。但是,它留下一个临时文件和一些临时变量。我为自己做了一个清洁的版本。
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | @ECHO OFF REM Source found on https://github.com/DieterDePaepe/windows-scripts REM Please share any improvements made! REM Code inspired by http://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w IF [%1]==[/?] GOTO :help IF [%1]==[/help] GOTO :help IF [%1]==[--help] GOTO :help IF [%1]==[] GOTO :main ECHO Unknown command: %1 EXIT /b 1 :help ECHO Refresh the environment variables in the console. ECHO. ECHO refreshEnv Refresh all environment variables. ECHO refreshEnv /? Display this help. GOTO :EOF :main REM Because the environment variables may refer to other variables, we need a 2-step approach. REM One option is to use delayed variable evaluation, but this forces use of SETLOCAL and REM may pose problems for files with an '!' in the name. REM The option used here is to create a temporary batch file that will define all the variables. REM Check to make sure we don't overwrite an actual file. IF EXIST %TEMP%\__refreshEnvironment.bat ( ECHO Environment refresh failed! ECHO. ECHO This script uses a temporary file"%TEMP%\__refreshEnvironment.bat", which already exists. The script was aborted in order to prevent accidental data loss. Delete this file to enable this script. EXIT /b 1 ) REM Read the system environment variables from the registry. FOR /F"usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"`) DO ( REM /I -> ignore casing, since PATH may also be called Path IF /I NOT [%%I]==[PATH] ( ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat ) ) REM Read the user environment variables from the registry. FOR /F"usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment`) DO ( REM /I -> ignore casing, since PATH may also be called Path IF /I NOT [%%I]==[PATH] ( ECHO SET %%I=%%K>>%TEMP%\__refreshEnvironment.bat ) ) REM PATH is a special variable: it is automatically merged based on the values in the REM system and user variables. REM Read the PATH variable from the system and user environment variables. FOR /F"usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PATH`) DO ( ECHO SET PATH=%%K>>%TEMP%\__refreshEnvironment.bat ) FOR /F"usebackq tokens=1,2,* skip=2" %%I IN (`REG QUERY HKCU\Environment /v PATH`) DO ( ECHO SET PATH=%%PATH%%;%%K>>%TEMP%\__refreshEnvironment.bat ) REM Load the variable definitions from our temporary file. CALL %TEMP%\__refreshEnvironment.bat REM Clean up after ourselves. DEL /Q %TEMP%\__refreshEnvironment.bat ECHO Environment successfully refreshed. |
如果您只需要刷新Windows中的环境变量,则可以从终端上运行refreshenv,而不是重新启动PC。
如果只涉及您要更改的一个(或几个)特定变量,我认为最简单的方法是一种解决方法:只需在您的环境中以及当前控制台会话中进行设置
- Set会将var放入您当前的会话中
- SetX会将var放入环境中,但不在当前会话中
我有这个简单的批处理脚本,可以将Maven从Java7更改为Java8(都是环境变量)批处理文件夹位于PATH变量中,因此我可以始终在控制台和环境中的JAVA_HOME变量中调用" j8"被更改:
j8.bat:
1 2 3 | @echo off set JAVA_HOME=%JAVA_HOME_8% setx JAVA_HOME"%JAVA_HOME_8%" |
到现在为止,我发现此方法最有效,最简单。
您可能希望将其放在一个命令中,但是在Windows中根本不存在...
首先安装choco:
-
如果使用cmd
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command"iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET"PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" -
如果使用Powershell
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
然后,您可以运行
我使用此Powershell脚本添加到PATH变量。
我相信,只要稍加调整,它也可以在您的情况下工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #REQUIRES -Version 3.0 if (-not ("win32.nativemethods" -as [type])) { # import sendmessagetimeout from win32 add-type -Namespace Win32 -Name NativeMethods -MemberDefinition @" [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout( IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); "@ } $HWND_BROADCAST = [intptr]0xffff; $WM_SETTINGCHANGE = 0x1a; $result = [uintptr]::zero function global:ADD-PATH { [Cmdletbinding()] param ( [parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)] [string] $Folder ) # See if a folder variable has been supplied. if (!$Folder -or $Folder -eq"" -or $Folder -eq $null) { throw 'No Folder Supplied. $ENV:PATH Unchanged' } # Get the current search path from the environment keys in the registry. $oldPath=$(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # See if the new Folder is already in the path. if ($oldPath | Select-String -SimpleMatch $Folder){ return 'Folder already within $ENV:PATH' } # Set the New Path and add the ; in front $newPath=$oldPath+';'+$Folder Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath -ErrorAction Stop # Show our results back to the world return 'This is the new PATH content: '+$newPath # notify all windows of environment block change [win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [uintptr]::Zero,"Environment", 2, 5000, [ref]$result) } function global:REMOVE-PATH { [Cmdletbinding()] param ( [parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)] [String] $Folder ) # See if a folder variable has been supplied. if (!$Folder -or $Folder -eq"" -or $Folder -eq $NULL) { throw 'No Folder Supplied. $ENV:PATH Unchanged' } # add a leading";" if missing if ($Folder[0] -ne";") { $Folder =";" + $Folder; } # Get the Current Search Path from the environment keys in the registry $newPath=$(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path # Find the value to remove, replace it with $NULL. If it's not found, nothing will change and you get a message. if ($newPath -match [regex]::Escape($Folder)) { $newPath=$newPath -replace [regex]::Escape($Folder),$NULL } else { return"The folder you mentioned does not exist in the PATH environment" } # Update the Environment Path Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath -ErrorAction Stop # Show what we just did return 'This is the new PATH content: '+$newPath # notify all windows of environment block change [win32.nativemethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [uintptr]::Zero,"Environment", 2, 5000, [ref]$result) } # Use ADD-PATH or REMOVE-PATH accordingly. #Anything to Add? #Anything to Remove? REMOVE-PATH"%_installpath_bin%" |
正如凯夫(Kev)所说,没有直接的方法。在大多数情况下,生成另一个CMD框更简单。更烦人的是,正在运行的程序也不知道更改(尽管IIRC可能会有广播消息要观看,以通知此类更改)。
情况更糟:在Windows的旧版本中,您必须先注销然后再登录以考虑所做的更改...
感谢您发布这个非常有趣的问题,即使在2019年(实际上,更新shell cmd也并不容易,因为它是如上所述的单个实例),因为在Windows中更新环境变量可以完成许多自动化任务而无需必须手动重新启动命令行。
例如,我们使用它来允许在我们定期重新安装的大量计算机上部署和配置软件。而且我必须承认,在部署软件期间必须重新启动命令行是非常不切实际的,并且将要求我们找到不一定令人满意的解决方法。
让我们解决我们的问题。
我们进行如下。
1-我们有一个批处理脚本,该脚本依次调用这样的powershell脚本
[文件:task.cmd]。
cmd
efresh.ps1
2-此后,refresh.ps1脚本使用注册表项(GetValueNames()等)更新环境变量。
然后,在相同的powershell脚本中,我们只需要调用可用的新环境变量即可。
例如,在典型情况下,如果我们之前使用无声命令在cmd上安装了nodeJS,则在调用该函数之后,我们可以直接调用npm在同一会话中安装以下特定软件包。
[文件:refresh.ps1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 } } Update-Environment #Here we can use newly added environment variables like for example npm install.. npm install -g create-react-app serve |
powershell脚本结束后,cmd脚本将继续执行其他任务。
现在,要记住的一件事是,在任务完成之后,即使powershell脚本已在其自己的会话中更新了这些环境变量,cmd仍然无法访问新的环境变量。这就是为什么我们在powershell脚本中执行所有必需的任务的原因,这些脚本当然可以调用与cmd相同的命令。
编辑:仅当您正在执行的环境更改是由于运行批处理文件而导致的时才有效。
如果批处理文件以
我写的几乎每个批处理文件都以
1 2 3 4 | ENDLOCAL & ( SET RESULT1=%RESULT1% SET RESULT2=%RESULT2% ) |
不,我不这么认为。尽管您可以手动设置它们。因此,您可以将它们放入批处理文件或其他文件中。
可能可以制作一个实用程序/脚本(如果还没有人的话)来查询注册表,并将当前环境设置为相同
为了解决这个问题,我同时使用setx和set更改了环境变量,然后重新启动了explorer.exe的所有实例。这样,随后启动的任何进程都将具有新的环境变量。
我的批处理脚本可以做到这一点:
1 2 3 4 5 6 | setx /M ENVVAR"NEWVALUE" set ENVVAR="NEWVALUE" taskkill /f /IM explorer.exe start explorer.exe >nul exit |
这种方法的问题在于,所有当前打开的资源管理器窗口都将关闭,这可能是个坏主意-但请参阅Kev的帖子以了解为什么这样做是必要的
或者您可以通过手动进行操作
To view or change environment variables: Right-click My Computer, and
then click Properties. Click the Advanced tab. Click Environment
variables. Click one the following options, for either a user or a
system variable: Click New to add a new variable name and value. Click
an existing variable, and then click Edit to change its name or value.
Click an existing variable, and then click Delete to remove it.
http://support.microsoft.com/kb/310519
Windows XP环境变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | %ALLUSERSPROFILE% (%PROGRAMDATA%) C:\Documents and Settings\All Users %APPDATA% C:\Documents and Settings\{username}\Application Data %COMPUTERNAME% {computername} %COMMONPROGRAMFILES% C:\Program Files\Common Files %COMMONPROGRAMFILES(x86)% C:\Program Files (x86)\Common Files %COMSPEC% C:\Windows\System32\cmd.exe %HOMEDRIVE% C: %HOMEPATH% \Documents and Settings\{username} %LOCALAPPDATA% Not available %LOGONSERVER% \\{domain_logon_server} %PATH% C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;{plus program paths} %PATHEXT% .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.WSF;.WSH %PROGRAMFILES% C:\Program Files %PROGRAMFILES(X86)% C:\Program Files (x86) (only in 64-bit version) %PROMPT% Code for current command prompt format. Code is usually $P$G %SystemDrive% C: %SystemRoot% The Windows directory, usually C:\Windows, formerly C:\WINNT %TEMP% and %TMP% C:\Documents and Settings\{username}\Local Settings\Temp %USERDOMAIN% {userdomain} %USERNAME% {username} %USERPROFILE% C:\Documents and Settings\{username} %WINDIR% C:\Windows %PUBLIC% %PROGRAMDATA% Only available in Windows Vista and newer versions %PSModulePath% |
Windows 7环境变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | %ALLUSERSPROFILE% (%PROGRAMDATA%) C:\ProgramData %APPDATA% C:\Users\{username}\AppData oaming %COMPUTERNAME% {computername} %COMMONPROGRAMFILES% C:\Program Files\Common Files %COMMONPROGRAMFILES(x86)% C:\Program Files (x86)\Common Files %COMSPEC% C:\Windows\System32\cmd.exe %HOMEDRIVE% C: %HOMEPATH% \Users\{username} %LOCALAPPDATA% C:\Users\{username}\AppData\Local %LOGONSERVER% \\{domain_logon_server} %PATH% C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;{plus program paths} %PATHEXT% .com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.msc %PROGRAMFILES% C:\Program Files %PROGRAMFILES(X86)% C:\Program Files (x86) (only in 64-bit version) %PROMPT% Code for current command prompt format. Code is usually $P$G %SystemDrive% C: %SystemRoot% C:\Windows %TEMP% and %TMP% C:\Users\{username}\AppData\Local\Temp %USERDOMAIN% {userdomain} %USERNAME% {username} %USERPROFILE% C:\Users\{username} %WINDIR% C:\Windows %PUBLIC% C:\Users\Public %PROGRAMDATA% C:\ProgramData %PSModulePath% %SystemRoot%\system32\WindowsPowerShell\v1.0\Modules\ |
希望这可以帮助。
只需在终端中输入"#-r"(不带引号#的-r选项)即可。
所有人都设置为默认路径:)