是否有命令从Windows中的命令提示符刷新环境变量?

Eri*_*ver 446 windows cmd environment-variables

如果我修改或添加环境变量,我必须重新启动命令提示符.是否有一个我可以执行的命令可以在不重新启动CMD的情况下执行此操作?

its*_*dok 132

您可以使用vbs脚本捕获系统环境变量,但是您需要一个bat脚本来实际更改当前环境变量,因此这是一个组合解决方案.

创建一个resetvars.vbs包含此代码的文件,并将其保存在路径中:

Set oShell = WScript.CreateObject("WScript.Shell")
filename = oShell.ExpandEnvironmentStrings("%TEMP%\resetvars.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
Run Code Online (Sandbox Code Playgroud)

创建另一个包含此代码的文件名resetvars.bat,位置相同:

@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"
Run Code Online (Sandbox Code Playgroud)

如果要刷新环境变量,只需运行即可 resetvars.bat


护教学:

我提出这个解决方案的两个主要问题是

一个.我找不到一种直接的方法将环境变量从vbs脚本导出回命令提示符,并且

PATH环境变量是用户和系统PATH变量的串联.

我不确定用户和系统之间冲突变量的一般规则是什么,所以我选择了用户覆盖系统,除了专门处理的PATH变量.

我使用奇怪的vbs + bat +临时bat机制来解决从vbs导出变量的问题.

注意:此脚本不会删除变量.

这可能会有所改善.

添加

如果需要将环境从一个cmd窗口导出到另一个cmd窗口,请使用此脚本(让我们称之为exportvars.vbs):

Set oShell = WScript.CreateObject("WScript.Shell")
filename = oShell.ExpandEnvironmentStrings("%TEMP%\resetvars.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
Run Code Online (Sandbox Code Playgroud)

运行exportvars.vbs中要导出的窗口,然后切换到要导出的窗口,并键入:

"%TEMP%\resetvars.bat"
Run Code Online (Sandbox Code Playgroud)

  • 也许你可以使用FOR/F"tokens = 1,*"%% c IN('resetvars.vbs')DO构造来避免临时文件 (2认同)
  • 正如我在答案中所说的"或者,在现有命令提示符中手动添加SET".这是有效的做法.但是答案很好. (2认同)
  • @itsadok - 鉴于这是现在接受的答案,你应该在开始时添加一个简短的解释,将脚本置于上下文中.即指出,如果不按上述方式手动更新或重新启动cmd.exe,则无法将env var更改传播到打开的cmd.exe. (2认同)

小智 101

这就是Chocolatey使用的.

https://github.com/chocolatey/choco/blob/master/src/chocolatey.resources/redirects/RefreshEnv.cmd

@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\Reg" 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\Reg" 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 .
Run Code Online (Sandbox Code Playgroud)

  • +1如果安装了Chocolatey,您只需运行`RefreshEnv`即可将更新的环境变量导入当前会话. (60认同)
  • 注意:Chocolatey已移动repos,可在此处找到此脚本的最新版本(修复了一些错误):https://github.com/chocolatey/choco/blob/master/src/chocolatey.resources/redirects/RefreshEnv. CMD (10认同)
  • 在 cmd/gitbash/PowerShell 中,这似乎对我根本不起作用 (3认同)
  • 这是一个非常有用的实用软件,非常感谢分享. (2认同)
  • 这也应该在“Powershell”中工作吗?它似乎只能从“cmd.exe”对我起作用。 (2认同)
  • 解决方案很好,但它修改了环境变量“TEMP”和“TMP”,将它们替换为存储在“HKCU\Environment”中的值。在我的例子中,我运行脚本来更新在 SYSTEM 帐户下运行的从属设备上由 Jenkins 作业修改的环境变量,因此 TEMP 和 TMP 被替换为 `%USERPROFILE%\AppData\Local\Temp` 而不是 `C:\Windows\温度`。这会破坏构建,因为链接器无法打开系统配置文件的 Temp 文件夹。 (2认同)

jol*_*lly 65

在Windows 7/8/10上,你可以安装Chocolatey,它有一个内置的脚本.

安装Chocolatey后,只需输入不带引号的"refreshenv".

  • 它不能开箱即用。您必须已经安装 Chocolatey,它会安装刷新脚本。说“在 Windows 7/8/10 中”具有误导性 (3认同)
  • 如果 refreshenv 过早地存在您的脚本(就像我所做的那样),您可以改用“调用 RefreshEnv.cmd”。(见 https://github.com/chocolatey/choco/issues/1461) (3认同)
  • 这是有效的答案,很高兴听到拒绝投票的人 (2认同)
  • 我究竟做错了什么?$> refreshenv'refreshenv'未被识别为内部或外部命令,可操作程序或批处理文件. (2认同)

Kev*_*Kev 58

根据设计,Windows 没有内置机制将环境变量add/change/remove传播到已经运行的cmd.exe,可以是另一个cmd.exe,也可以是"我的电脑 - >属性 - >高级设置 - >环境变量".

如果在现有打开命令提示符的范围之外修改或添加新环境变量,则需要重新启动命令提示符,或者在现有命令提示符中使用SET手动添加.

最新接受的答案显示了手动刷新局部变通的所有环境变量的脚本.该脚本在"我的电脑...环境变量"中处理全局更改环境变量的用例,但如果在一个cmd.exe中更改了环境变量,则脚本不会将其传播到另一个正在运行的cmd.exe.

  • 这个答案的负面评论和缩写标记显示了堆栈溢出有时是多么破碎.凯夫给出了正确的答案.仅仅因为你不喜欢它是没有理由把它标记下来. (6认同)
  • 而且令人讨厌的是,cmd.exe的额外实例不计算在内.在更改反映在任何新的cmd.exe中之前,它们都必须被杀死. (4认同)

wha*_*g28 36

在找到更简单的解决方案之前,我遇到了这个答案.

只需explorer.exe在任务管理器中重启

我没有测试,但您可能还需要重新打开命令提示符.

感谢蒂莫Huovinen这里:节点无法识别,虽然安装成功(如果这帮助了你,请去给这人的评论信用).

  • 问题是:"是否有一个我可以执行的命令可以执行此操作*而无需重新启动CMD*?" (7认同)
  • 该解决方案帮助我在Windows 10中 (4认同)
  • 好的解决方案,谢谢!要扩展并解决 @Oscar 的评论:以管理员身份启动“cmd”窗口。使用命令“taskkill /f /im explorer.exe && explorer.exe”。这将终止 explorer.exe 进程并重新启动它。 (3认同)
  • 与仅重新启动命令提示符相比,这有什么好处? (3认同)

小智 32

这适用于Windows 7: SET PATH=%PATH%;C:\CmdShortcuts

通过键入echo%PATH%进行测试,它运行良好.还设置如果你打开一个新的cmd,不再需要那些讨厌的重新启动:)

  • 这并不能解决被问到的问题,也不能解决问题.最初的问题是如何将环境变量刷新到已设置在该终端之外的值. (26认同)

Jen*_*och 25

使用"setx"并重新启动cmd提示符

此作业有一个名为" setx " 的命令行工具.它用于读取和写入 env变量.命令窗口关闭后,变量仍然存在.

它"在用户或系统环境中创建或修改环境变量,无需编程或编写脚本.setx命令还检索注册表项的值并将它们写入文本文件."

注意:此工具创建或修改的变量将在以后的命令窗口中可用,但在当前的CMD.exe命令窗口中不可用.所以,你必须重新启动.

如果setx遗失:


或者修改注册表

MSDN说:

若要以编程方式添加或修改系统环境变量,将它们添加到 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment注册表项,然后广播WM_SETTINGCHANGE 消息,并将lParam设置为字符串" Environment ".

这允许应用程序(如shell)获取更新.

  • setx /?在一个说明中说:"在本地系统上,此工具创建或修改的变量将在未来的命令窗口中可用,但**不在当前的**CMD.exe命令窗口中." OP想要更新当前的cmd. (5认同)
  • 买家要小心!如果你有一个特别长的'%PATH%`那么`setx`可能会将其截断为1024字节!_就这样,他的晚上消失了_ (4认同)
  • 当前系统环境:`HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE`当前用户环境:`HKEY_CURRENT_USER\Environment\VARIABLE` (3认同)
  • setx VARIABLE -k "HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\CurrentVersion" echo %VARIABLE% (2认同)

小智 15

调用此函数对我有用:

VOID Win32ForceSettingsChange()
{
    DWORD dwReturnValue;
    ::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
Run Code Online (Sandbox Code Playgroud)

  • 并非所有程序都听取此消息(实际上大多数程序可能都没有) (8认同)

Bad*_*ers 13

我为 cmd 和 cygwin 制作了一个更好的 Chocolatey Refreshenv 替代品,它解决了很多问题,例如:

\n
    \n
  • 如果变量有一些 \ncmd 元字符,那么Chocolateyfreshenv就会很糟糕,请参阅此测试:

    \n

    将其添加到 HKCU\\Environment: 中的路径中test & echo baaaaaaaaaad,\n然后运行 ​​Chocolatey,refreshenv您将看到它打印\n baaaaaaaaaad,这非常糟糕,并且新路径不会添加到\n您的路径变量中。

    \n

    这个脚本解决了这个问题,您可以使用任何元字符来测试它,甚至是一些非常糟糕的字符,例如:

    \n
    ; & % \' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \\ / " : ? * = . - _ & echo baaaad\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • freshenv 仅添加系统用户\n环境变量,但 CMD 也添加了易失性变量\n(HKCU\\Volatile Environment)。该脚本将合并所有三个并删除所有重复项

    \n
  • \n
  • freshenv 重置你的路径。此脚本将新路径追加到调用此脚本的父脚本的\n旧路径中。这比覆盖旧路径要好,否则它将删除父脚本新添加的任何路径。

    \n
  • \n
  • 该脚本解决了 @Gene\nMayevsky 的评论中描述的这个问题:refreshenv修改环境变量 TEMP 和 TMP,将它们替换为存储在 HKCU\\Environment 中的值。在我的例子中,我运行\n脚本来更新由 Jenkins 作业在 SYSTEM 帐户下运行的从站上修改的环境变量,因此 TEMP 和 TMP 被 %USERPROFILE%\\AppData\\Local\\Temp 替代C:\\Windows\\Temp。这会破坏构建,因为链接器无法打开系统配置文件的临时文件夹。

    \n
  • \n
\n

我为 cmd 制作了一个脚本,为 cygwin/bash 制作了另一个脚本,\n您可以在这里找到它们: https: //github.com/badrelmers/RefrEnv

\n

对于命令

\n

该脚本使用 vbscript,因此它适用于所有 Windows 版本xp+

\n

使用它时将其另存为refrenv.bat并调用它call refrenv.bat

\n
<!-- : Begin batch script\n@echo off\nREM PUSHD "%~dp0"\n\n\nREM author: Badr Elmers 2021\nREM description: refrenv = refresh environment. this is a better alternative to the chocolatey refreshenv for cmd\nREM https://github.com/badrelmers/RefrEnv\nREM /sf/ask/12011191/\n\nREM ___USAGE_____________________________________________________________\nREM usage: \nREM        call refrenv.bat        full refresh. refresh all non critical variables*, and refresh the PATH\n\nREM debug:\nREM        to debug what this script do create this variable in your parent script like that\nREM        set debugme=yes\nREM        then the folder containing the files used to set the variables will be open. Then see\nREM        _NewEnv.cmd this is the file which run inside your script to setup the new variables, you\nREM        can also revise the intermediate files _NewEnv.cmd_temp_.cmd and _NewEnv.cmd_temp2_.cmd \nREM        (those two contains all the variables before removing the duplicates and the unwanted variables)\n\n\nREM you can also put this script in windows\\systems32 or another place in your %PATH% then call it from an interactive console by writing refrenv\n\nREM *critical variables: are variables which belong to cmd/windows and should not be refreshed normally like:\nREM - windows vars:\nREM ALLUSERSPROFILE APPDATA CommonProgramFiles CommonProgramFiles(x86) CommonProgramW6432 COMPUTERNAME ComSpec HOMEDRIVE HOMEPATH LOCALAPPDATA LOGONSERVER NUMBER_OF_PROCESSORS OS PATHEXT PROCESSOR_ARCHITECTURE PROCESSOR_ARCHITEW6432 PROCESSOR_IDENTIFIER PROCESSOR_LEVEL PROCESSOR_REVISION ProgramData ProgramFiles ProgramFiles(x86) ProgramW6432 PUBLIC SystemDrive SystemRoot TEMP TMP USERDOMAIN USERDOMAIN_ROAMINGPROFILE USERNAME USERPROFILE windir SESSIONNAME\n\n\nREM ___INFO_____________________________________________________________\nREM :: this script reload environment variables inside cmd every time you want environment changes to propagate, so you do not need to restart cmd after setting a new variable with setx or when installing new apps which add new variables ...etc\n\n\nREM This is a better alternative to the chocolatey refreshenv for cmd, which solves a lot of problems like:\n\nREM The Chocolatey refreshenv is so bad if the variable have some cmd meta-characters, see this test:\n    REM add this to the path in HKCU\\Environment: test & echo baaaaaaaaaad, and run the chocolatey refreshenv you will see that it prints baaaaaaaaaad which is very bad, and the new path is not added to your path variable.\n    REM This script solve this and you can test it with any meta-character, even something so bad like:\n    REM ; & % \' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \\ / " : ? * = . - _ & echo baaaad\n    \nREM refreshenv adds only system and user environment variables, but CMD adds volatile variables too (HKCU\\Volatile Environment). This script will merge all the three and remove any duplicates.\n\nREM refreshenv reset your PATH. This script append the new path to the old path of the parent script which called this script. It is better than overwriting the old path, otherwise it will delete any newly added path by the parent script.\n\nREM This script solve this problem described in a comment by @Gene Mayevsky: refreshenv modifies env variables TEMP and TMP replacing them with values stored in HKCU\\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that\'s running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\\AppData\\Local\\Temp instead of C:\\Windows\\Temp. This breaks build because linker cannot open system profile\'s Temp folder.\n\nREM ________\nREM this script solve things like that too:\nREM The confusing thing might be that there are a few places to start the cmd from. In my case I run cmd from windows explorer and the environment variables did not change while when starting cmd from the "run" (windows key + r) the environment variables were changed.\n\nREM In my case I just had to kill the windows explorer process from the task manager and then restart it again from the task manager.\nREM Once I did this I had access to the new environment variable from a cmd that was spawned from windows explorer.\n\nREM my conclusion:\nREM if I add a new variable with setx, i can access it in cmd only if i run cmd as admin, without admin right i have to restart explorer to see that new variable. but running this script inside my script (who sets the variable with setx) solve this problem and i do not have to restart explorer\n\n\nREM ________\nREM windows recreate the path using three places at less:\nREM the User namespace:    HKCU\\Environment\nREM the System namespace:  HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\nREM the Session namespace: HKCU\\Volatile Environment\nREM but the original chocolatey script did not add the volatile path. This script will merge all the three and remove any duplicates. this is what windows do by default too\n\nREM there is this too which cmd seems to read when first running, but it contains only TEMP and TMP,so i will not use it\nREM HKEY_USERS\\.DEFAULT\\Environment\n\n\nREM ___TESTING_____________________________________________________________\nREM to test this script with extreme cases do\n    REM :: Set a bad variable\n    REM add a var in reg HKCU\\Environment as the following, and see that echo is not executed.  if you use refreshenv of chocolatey you will see that echo is executed which is so bad!\n    REM so save this in reg:\n    REM all 32 characters: & % \' ( ) ~ + @ # $ { } [ ] ; , ` ! ^ | > < \\ / " : ? * = . - _ & echo baaaad\n    REM and this:\n    REM (^.*)(Form Product=")([^"]*") FormType="[^"]*" FormID="([0-9][0-9]*)".*$\n    REM and use set to print those variables and see if they are saved without change ; refreshenv fail dramatically with those variables\n    \n    \nREM invalid characters (illegal characters in file names) in Windows using NTFS\nREM \\ / : * ? "  < > |  and ^ in FAT \n\n\n\nREM __________________________________________________________________________________________\nREM __________________________________________________________________________________________\nREM __________________________________________________________________________________________\nREM this is a hybrid script which call vbs from cmd directly\nREM :: The only restriction is the batch code cannot contain - - > (without space between - - > of course)\nREM :: The only restriction is the VBS code cannot contain </script>.\nREM :: The only risk is the undocumented use of "%~f0?.wsf" as the script to load. Somehow the parser properly finds and loads the running .BAT script "%~f0", and the ?.wsf suffix mysteriously instructs CSCRIPT to interpret the script as WSF. Hopefully MicroSoft will never disable that "feature".\nREM :: /sf/ask/635213351/\n\nif "%debugme%"=="yes" (\n    echo RefrEnv - Refresh the Environment for CMD - ^(Debug enabled^)\n) else (\n    echo RefrEnv - Refresh the Environment for CMD\n)\n\nset "TEMPDir=%TEMP%\\refrenv"\nIF NOT EXIST "%TEMPDir%" mkdir "%TEMPDir%"\nset "outputfile=%TEMPDir%\\_NewEnv.cmd"\n\n\nREM detect if DelayedExpansion is enabled\nREM It relies on the fact, that the last caret will be removed only in delayed mode.\nREM https://www.dostips.com/forum/viewtopic.php?t=6496\nset "DelayedExpansionState=IsDisabled"\nIF "^!" == "^!^" (\n    REM echo DelayedExpansion is enabled\n    set "DelayedExpansionState=IsEnabled"\n)\n\n\nREM :: generate %outputfile% which contain all the new variables\nREM cscript //nologo "%~f0?.wsf" %1\ncscript //nologo "%~f0?.wsf" "%outputfile%" %DelayedExpansionState%\n\n\nREM ::set the new variables generated with vbscript script above\nREM for this to work always it is necessary to use DisableDelayedExpansion or escape ! and ^ when using EnableDelayedExpansion, but this script already solve this, so no worry about that now, thanks to God\nREM test it with some bad var like:\nREM all 32 characters: ; & % \' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \\ / " : ? * = . - _ & echo baaaad\nREM For /f delims^=^ eol^= %%a in (%outputfile%) do %%a\nREM for /f "delims== tokens=1,2" %%G in (%outputfile%) do set "%%G=%%H"\nFor /f delims^=^ eol^= %%a in (%outputfile%) do set %%a\n\n\nREM for safely print a variable with bad charachters do:\nREM SETLOCAL EnableDelayedExpansion\nREM echo "!z9!"\nREM or\nREM set z9\nREM but generally paths and environment variables should not have bad metacharacters, but it is not a rule!\n\n\nif "%debugme%"=="yes" (\n    explorer "%TEMPDir%"\n) else (\n    rmdir /Q /S "%TEMPDir%"\n)\n\nREM cleanup\nset "TEMPDir="\nset "outputfile="\nset "DelayedExpansionState="\nset "debugme="\n\n\nREM pause\nexit /b\n\n\n\nREM #############################################################################\nREM :: to run jscript you have to put <script language="JScript"> directly after ----- Begin wsf script --->\n----- Begin wsf script --->\n<job><script language="VBScript">\nREM #############################################################################\nREM ### put you code here #######################################################\nREM #############################################################################\n\nREM based on itsadok script from here\nREM /sf/ask/12011191/\n\nREM and it is faster as stated by this comment\nREM While I prefer the Chocolatey code-wise for being pure batch code, overall I decided to use this one, since it\'s faster. (~0.3 seconds instead of ~1 second -- which is nice, since I use it frequently in my Explorer "start cmd here" entry) \xe2\x80\x93 \n\nREM and it is safer based on my tests, the Chocolatey refreshenv is so bad if the variable have some cmd metacharacters\n\n\nConst ForReading = 1 \nConst ForWriting = 2\nConst ForAppending = 8 \n\nSet WshShell = WScript.CreateObject("WScript.Shell")\nfilename=WScript.Arguments.Item(0)\nDelayedExpansionState=WScript.Arguments.Item(1)\n\nTMPfilename=filename & "_temp_.cmd"\nSet fso = CreateObject("Scripting.fileSystemObject")\nSet tmpF = fso.CreateTextFile(TMPfilename, TRUE)\n\n\nset oEnvS=WshShell.Environment("System")\nfor each sitem in oEnvS\n    tmpF.WriteLine(sitem)\nnext\nSystemPath = oEnvS("PATH")\n\nset oEnvU=WshShell.Environment("User")\nfor each sitem in oEnvU\n    tmpF.WriteLine(sitem)\nnext\nUserPath = oEnvU("PATH")\n\nset oEnvV=WshShell.Environment("Volatile")\nfor each sitem in oEnvV\n    tmpF.WriteLine(sitem)\nnext\nVolatilePath = oEnvV("PATH")\n\nset oEnvP=WshShell.Environment("Process")\nREM i will not save the process env but only its path, because it have strange variables like  =::=::\\ and  =F:=.... which seems to be added by vbscript\nREM for each sitem in oEnvP\n    REM tmpF.WriteLine(sitem)\nREM next\nREM here we add the actual session path, so we do not reset the original path, because maybe the parent script added some folders to the path, If we need to reset the path then comment the following line\nProcessPath = oEnvP("PATH")\n\nREM merge System, User, Volatile, and process PATHs\nNewPath = SystemPath & ";" & UserPath & ";" & VolatilePath & ";" & ProcessPath\n\n\nREM ________________________________________________________________\nREM :: remove duplicates from path\nREM :: expand variables so they become like windows do when he read reg and create path, then Remove duplicates without sorting \n    REM why i will clean the path from duplicates? because:\n    REM the maximum string length in cmd is 8191 characters. But string length doesnt mean that you can save 8191 characters in a variable because also the assignment belongs to the string. you can save 8189 characters because the remaining 2 characters are needed for "a="\n   \n    REM based on my tests: \n    REM when i open cmd as user , windows does not remove any duplicates from the path, and merge system+user+volatil path\n    REM when i open cmd as admin, windows do: system+user path (here windows do not remove duplicates which is stupid!) , then it adds volatil path after removing from it any duplicates \n\nREM \' https://www.rosettacode.org/wiki/Remove_duplicate_elements#VBScript\nFunction remove_duplicates(list)\n    arr = Split(list,";")\n    Set dict = CreateObject("Scripting.Dictionary")\n    REM \' force dictionary compare to be case-insensitive , uncomment to force case-sensitive\n    dict.CompareMode = 1\n\n    For i = 0 To UBound(arr)\n        If dict.Exists(arr(i)) = False Then\n            dict.Add arr(i),""\n        End If\n    Next\n    For Each key In dict.Keys\n        tmp = tmp & key & ";"\n    Next\n    remove_duplicates = Left(tmp,Len(tmp)-1)\nEnd Function\n \nREM expand variables\nNewPath = WshShell.ExpandEnvironmentStrings(NewPath)\nREM remove duplicates\nNewPath=remove_duplicates(NewPath)\n\nREM remove_duplicates() will add a ; to the end so lets remove it if the last letter is ;\nIf Right(NewPath, 1) = ";" Then \n    NewPath = Left(NewPath, Len(NewPath) - 1) \nEnd If\n  \ntmpF.WriteLine("PATH=" & NewPath)\ntmpF.Close\n\nREM ________________________________________________________________\nREM :: exclude setting variables which may be dangerous to change\n\n    REM when i run a script from task scheduler using SYSTEM user the following variables are the differences between the scheduler env and a normal cmd script, so i will not override those variables\n    REM APPDATA=D:\\Users\\LLED2\\AppData\\Roaming\n    REM APPDATA=D:\\Windows\\system32\\config\\systemprofile\\AppData\\Roaming\n\n    REM LOCALAPPDATA=D:\\Users\\LLED2\\AppData\\Local\n    REM LOCALAPPDATA=D:\\Windows\\system32\\config\\systemprofile\\AppData\\Local\n\n    REM TEMP=D:\\Users\\LLED2\\AppData\\Local\\Temp\n    REM TEMP=D:\\Windows\\TEMP\n\n    REM TMP=D:\\Users\\LLED2\\AppData\\Local\\Temp\n    REM TMP=D:\\Windows\\TEMP\n\n    REM USERDOMAIN=LLED2-PC\n    REM USERDOMAIN=WORKGROUP\n\n    REM USERNAME=LLED2\n    REM USERNAME=LLED2-PC$\n\n    REM USERPROFILE=D:\\Users\\LLED2\n    REM USERPROFILE=D:\\Windows\\system32\\config\\systemprofile\n\n    REM i know this thanks to this comment\n    REM The solution is good but it modifies env variables TEMP and TMP replacing them with values stored in HKCU\\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that\'s running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\\AppData\\Local\\Temp instead of C:\\Windows\\Temp. This breaks build because linker cannot open system profile\'s Temp folder. \xe2\x80\x93 Gene Mayevsky Sep 26 \'19 at 20:51\n\n\nREM Delete Lines of a Text File Beginning with a Specified String\nREM those are the variables which should not be changed by this script \narrBlackList = Array("ALLUSERSPROFILE=", "APPDATA=", "CommonProgramFiles=", "CommonProgramFiles(x86)=", "CommonProgramW6432=", "COMPUTERNAME=", "ComSpec=", "HOMEDRIVE=", "HOMEPATH=", "LOCALAPPDATA=", "LOGONSERVER=", "NUMBER_OF_PROCESSORS=", "OS=", "PATHEXT=", "PROCESSOR_ARCHITECTURE=", "PROCESSOR_ARCHITEW6432=", "PROCESSOR_IDENTIFIER=", "PROCESSOR_LEVEL=", "PROCESSOR_REVISION=", "ProgramData=", "ProgramFiles=", "ProgramFiles(x86)=", "ProgramW6432=", "PUBLIC=", "SystemDrive=", "SystemRoot=", "TEMP=", "TMP=", "USERDOMAIN=", "USERDOMAIN_ROAMINGPROFILE=", "USERNAME=", "USERPROFILE=", "windir=", "SESSIONNAME=")\n\nSet objFS = CreateObject("Scripting.FileSystemObject")\nSet objTS = objFS.OpenTextFile(TMPfilename, ForReading)\nstrContents = objTS.ReadAll\nobjTS.Close\n\nTMPfilename2= filename & "_temp2_.cmd"\narrLines = Split(strContents, vbNewLine)\nSet objTS = objFS.OpenTextFile(TMPfilename2, ForWriting, True)\n\nREM this is the equivalent of findstr /V /I /L  or  grep -i -v  , i don t know a better way to do it, but it works fine\nFor Each strLine In arrLines\n    bypassThisLine=False\n    For Each BlackWord In arrBlackList\n        If Left(UCase(LTrim(strLine)),Len(BlackWord)) = UCase(BlackWord) Then\n            bypassThisLine=True\n        End If\n    Next\n    If bypassThisLine=False Then\n        objTS.WriteLine strLine\n    End If\nNext\n\nREM ____________________________________________________________\nREM :: expand variables because registry save some variables as unexpanded %....%\nREM :: and escape ! and ^ for cmd EnableDelayedExpansion mode\n\nset f=fso.OpenTextFile(TMPfilename2,ForReading)\nREM Write file:  ForAppending = 8 ForReading = 1 ForWriting = 2 , True=create file if not exist\nset fW=fso.OpenTextFile(filename,ForWriting,True)\nDo Until f.AtEndOfStream\n    LineContent = f.ReadLine\n    REM expand variables\n    LineContent = WshShell.ExpandEnvironmentStrings(LineContent)\n    \n    REM _____this part is so important_____\n    REM if cmd delayedexpansion is enabled in the parent script which calls this script then bad thing happen to variables saved in the registry if they contain ! . if var have ! then ! and ^ are removed; if var do not have ! then ^ is not removed . to understand what happens read this :\n    REM how cmd delayed expansion parse things\n    REM /sf/ask/286628961/#7970912\n    REM For each parsed token, first check if it contains any !. If not, then the token is not parsed - important for ^ characters. If the token does contain !, then scan each character from left to right:\n    REM     - If it is a caret (^) the next character has no special meaning, the caret itself is removed\n    REM     - If it is an exclamation mark, search for the next exclamation mark (carets are not observed anymore), expand to the value of the variable.\n    REM         - Consecutive opening ! are collapsed into a single !\n    REM         - Any remaining unpaired ! is removed\n    REM ...\n    REM Look at next string of characters, breaking before !, :, or <LF>, and call them VAR\n\n    REM conclusion:\n    REM when delayedexpansion is enabled and var have ! then i have to escape ^ and ! ,BUT IF VAR DO NOT HAVE ! THEN DO NOT ESCAPE ^  .this made me crazy to discover\n    REM when delayedexpansion 

  • 我刚刚测试了 Git bash,它对我来说工作得很好,请参阅 https://imgur.com/sQS84QI – 请在 github 中打开一个问题,以便我们可以讨论这个问题,看看为什么它不适合你:https://github。 com/badrelmers/RefrEnv/issues (4认同)

Chr*_*mes 11

我想出的最好的方法是只进行注册表查询.这是我的例子.

在我的示例中,我使用添加了新环境变量的Batch文件进行了安装.我需要在安装完成后立即执行此操作,但无法使用这些新变量生成新进程.我测试了产生另一个浏览器窗口并回调cmd.exe并且这有效但是在Vista和Windows 7上,资源管理器仅作为单个实例运行,并且通常作为登录的人运行.这将自动失败,因为我需要我的管理员信誉无论是从本地系统运行还是作为管理员运行,都可以执行操作.对此的限制是它不处理像path这样的东西,这只适用于简单的环境变量.这允许我使用批处理来到目录(带空格)并复制文件运行.exes等.这是今天从stackoverflow.com上的may资源写的.

原始批次调用新批次:

testenvget.cmd SDROOT(或任何变量)

@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
Run Code Online (Sandbox Code Playgroud)

还有另一种方法,我从各种不同的想法中提出.请看下面.这基本上会从注册表获取最新的路径变量但是,这将导致一些问题,因为注册表查询本身会给出变量,这意味着每个地方都有一个变量,这将无法工作,所以要解决这个问题我基本上加倍了路径.非常讨厌.更多的方法是:Set Path =%Path%; C:\ Program Files\Software .... \

无论这里是新的批处理文件,请谨慎使用.

@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
Run Code Online (Sandbox Code Playgroud)


jos*_*ley 7

可以通过在指定进程本身内覆盖环境表来完成此操作.

作为概念验证,我编写了这个示例应用程序,它只是在cmd.exe进程中编辑了一个(已知的)环境变量:

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\n", 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)\n", 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)\n", status);
    }
    printf("PEB: %p\n", 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\n", processParameters);
    }
    else
    {
        printf("Error ReadProcessMemory (%u)\n", 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\n", 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\n", 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)\n", GetLastError());
        }
    }

    // cleanup
    delete[] localEnvBlock;
    CloseHandle(hProcess);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

>set ENVTEST=abc

>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528

>set ENVTEST
ENVTEST=def
Run Code Online (Sandbox Code Playgroud)

笔记

这种方法也仅限于安全限制.如果目标是在更高的海拔或更高的帐户(例如SYSTEM)运行,那么我们将无权编辑其内存.

如果您想对32位应用程序执行此操作,则上面的硬编码偏移量将分别更改为0x10和0x48.这些偏移可以通过(在WinDbg中例如在调试器倾出_PEB和_RTL_USER_PROCESS_PARAMETERS结构中找到dt _PEBdt _RTL_USER_PROCESS_PARAMETERS)

要将概念验证更改为OP所需的内容,它只需枚举当前系统和用户环境变量(例如@ tsadok的答案记录),并将整个环境表写入目标进程的内存中.

编辑:环境块的大小也存储在_RTL_USER_PROCESS_PARAMETERS结构中,但内存是在进程堆上分配的.因此,从外部流程我们无法调整大小并使其变大.我一直在使用VirtualAllocEx在目标进程中为环境存储分配额外的内存,并且能够设置和读取一个全新的表.不幸的是,任何尝试从正常方式修改环境都会崩溃并烧毁,因为地址不再指向堆(它将在RtlSizeHeap中崩溃).


Alg*_*aut 6

环境变量保存在HKEY_LOCAL_MACHINE\SYSTEM\ControlSet\Control\Session Manager\Environment中.

许多有用的env变量(如Path)都存储为REG_SZ.有几种方法可以访问注册表,包括REGEDIT:

REGEDIT /E &lt;filename&gt; "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"

输出以幻数开头.因此,要使用find命令搜索它,需要对其进行输入和重定向:type <filename> | findstr -c:\"Path\"

因此,如果您只想使用系统属性中的内容刷新当前命令会话中的路径变量,则以下批处理脚本可以正常工作:

RefreshPath.cmd:


    @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%\newpath
       )

     ENDLOCAL

     for /f "tokens=*" %%i in (%temp%\newpath) do set path=%%i

  • 环境变量**不会**保存在注册表中.注册表中保存的是_template_,Windows资源管理器(重新)等程序构建其环境变量[通知时] [http://serverfault.com/questions/240570/windows-environment-variables-和手动注册表编辑,没有错价值观问题/ 241012#241012).实际环境变量是按进程存储的,并存储在每个进程自己的地址空间中,最初从其父进程继承,然后在进程'奇思妙想时可修改. (5认同)

小智 6

重新启动资源管理器为我做了这个,但仅适用于新的 cmd 终端。

我设置路径的终端已经可以看到新的 Path 变量(在 Windows 7 中)。

taskkill /f /im explorer.exe && explorer.exe
Run Code Online (Sandbox Code Playgroud)


est*_*bro 5

尝试以管理员身份打开新的命令提示符。这在Windows 10上对我有用。(我知道这是个老答案,但是我不得不分享这个,因为仅为此写一个VBS脚本是荒谬的)。


小智 5

在当前会话中不重新启动变量的情况下,将变量添加到路径的最简单方法是打开命令提示符并键入:

PATH=(VARIABLE);%path%
Run Code Online (Sandbox Code Playgroud)

然后按enter

检查您的变量是否已加载,键入

PATH
Run Code Online (Sandbox Code Playgroud)

然后按enter。但是,在重新启动之前,变量将仅是路径的一部分。


Dan*_*eim 5

令人困惑的事情可能是有几个地方可以开始cmd。在我来说,我跑了从资源管理器窗口在cmd和环境变量并没有改变开始的时候,而从“运行” CMD(Windows键+ R)环境变量发生了变化

就我而言,我只需要从任务管理器中终止Windows资源管理器进程,然后再从任务管理器中重新启动它即可

完成此操作后,我可以从Windows资源管理器中生成的cmd中访问新的环境变量。


Cha*_*ald 5

我已经使用了几年的解决方案:

@echo off
rem Refresh PATH from registry.
setlocal
set USR_PATH=
set SYS_PATH=
for /F "tokens=3* skip=2" %%P in ('%SystemRoot%\system32\reg.exe query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v PATH') do @set "SYS_PATH=%%P %%Q"
for /F "tokens=3* skip=2" %%P in ('%SystemRoot%\system32\reg.exe query "HKCU\Environment" /v PATH') do @set "USR_PATH=%%P %%Q"
if "%SYS_PATH:~-1%"==" " set "SYS_PATH=%SYS_PATH:~0,-1%"
if "%USR_PATH:~-1%"==" " set "USR_PATH=%USR_PATH:~0,-1%"
endlocal & call set "PATH=%SYS_PATH%;%USR_PATH%"
goto :EOF
Run Code Online (Sandbox Code Playgroud)

编辑:糟糕,这是更新版本。


归档时间:

查看次数:

499537 次

最近记录:

6 年,2 月 前