当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《是否有命令从Windows中的命令提示符刷新环境变量?》经验,为你挑选了14个好方法。

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



1> itsadok..:

您可以使用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

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

@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"

如果要刷新环境变量,只需运行即可 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

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

"%TEMP%\resetvars.bat"


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

2> 小智..:

这就是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 .


+1如果安装了Chocolatey,您只需运行`RefreshEnv`即可将更新的环境变量导入当前会话.
注意:Chocolatey已移动repos,可在此处找到此脚本的最新版本(修复了一些错误):https://github.com/chocolatey/choco/blob/master/src/chocolatey.resources/redirects/RefreshEnv. CMD
这是一个非常有用的实用软件,非常感谢分享.

3> jolly..:

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

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


我究竟做错了什么?$> refreshenv'refreshenv'未被识别为内部或外部命令,可操作程序或批处理文件.

4> Kev..:

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

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

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


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

5> wharding28..:

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

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

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

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


问题是:"是否有一个我可以执行的命令可以执行此操作*而无需重新启动CMD*?"
该解决方案帮助我在Windows 10中
与仅重新启动命令提示符相比,这有什么好处?

6> 小智..:

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

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


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

7> Jens A. Koch..:

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

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

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

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

如果setx遗失:

http://download.microsoft.com/download/win2000platform/setx/1.00.0.1/nt5/en-us/setx_setup.exe


或者修改注册表

MSDN说:

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

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


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

8> 小智..:

调用此函数对我有用:

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


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

9> Christopher ..:

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

在我的示例中,我使用添加了新环境变量的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

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



10> josh poley..:

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

作为概念验证,我编写了这个示例应用程序,它只是在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;
}

样本输出:

>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.这些偏移可以通过(在WinDbg中例如在调试器倾出_PEB和_RTL_USER_PROCESS_PARAMETERS结构中找到dt _PEBdt _RTL_USER_PROCESS_PARAMETERS)

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

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



11> Algonaut..:

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

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

REGEDIT /E <filename> "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"

输出以幻数开头.因此,要使用find命令搜索它,需要对其进行输入和重定向:type | 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).实际环境变量是按进程存储的,并存储在每个进程自己的地址空间中,最初从其父进程继承,然后在进程'奇思妙想时可修改.

12> estebro..:

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



13> 小智..:

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

PATH=(VARIABLE);%path%

然后按enter

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

PATH

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



14> Daniel Fenst..:

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

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

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

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有