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

时间:2008-10-05 06:49:38

标签: windows cmd environment-variables

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

30 个答案:

答案 0 :(得分:127)

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

即可

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

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

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

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

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

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

这可能会有所改善。

<强> ADDED

如果您需要将环境从一个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"

答案 1 :(得分:86)

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

答案 2 :(得分:55)

根据设计,Windows没有内置机制将环境变量add / change / remove传播到已经运行的cmd.exe,可以是来自另一个cmd.exe,也可以是“我的”计算机 - &gt;属性 - &gt;高级设置 - &gt;环境变量“。

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

latest accepted answer通过在脚本中手动刷新所有环境变量来显示部分解决方法。该脚本在“我的电脑...环境变量”中处理全局更改环境变量的用例,但如果在一个cmd.exe中更改了环境变量,则脚本不会将其传播到另一个正在运行的cmd.exe。

答案 3 :(得分:46)

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

安装Chocolatey后,只需输入不带引号的“refreshenv”。

答案 4 :(得分:34)

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

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

答案 5 :(得分:31)

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

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

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

此处归Timo Huovinen所示:Node not recognized although successfully installed(如果这对你有所帮助,请给这位男士的评论留言)。

答案 6 :(得分:25)

使用“setx”并重新启动cmd提示

此作业有一个名为“setx”的命令行工具。 这是读写 env变量。 命令窗口关闭后,变量仍然存在。

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

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

如果缺少setx


或修改注册表

MSDN说:

  

要以编程方式添加或修改系统环境变量,请添加   他们到了   的 HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \控制\会话   Manager \ Environment 注册表项,然后广播 WM_SETTINGCHANGE    lParam 设置为字符串“环境”的消息。

     

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

答案 7 :(得分:13)

调用此函数对我有用:

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

答案 8 :(得分:11)

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

在我的示例中,我使用添加了新环境变量的Batch文件进行了安装。我需要在安装完成后立即执行此操作,但无法使用这些新变量生成新进程。我测试了产生另一个浏览器窗口并回调cmd.exe并且这有效但是在Vista和Windows 7上,Explorer只作为单个实例运行,通常作为登录的人运行。这将自动失败,因为我需要我的管理员信誉无论是从本地系统运行还是作为管理员运行,都可以执行操作。对此的限制是它不处理像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

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

答案 9 :(得分: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;
}

示例输出:

>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 dt _PEBdt _RTL_USER_PROCESS_PARAMETERS中)

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

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

答案 10 :(得分:5)

令人困惑的事情可能是有几个地方可以启动cmd。 在我的情况下,我从Windows资源管理器运行 cmd ,而环境变量没有改变,而从“运行”启动 cmd (Windows键+ r)环境变量已更改

在我的情况下,我只需从任务管理器中杀死Windows资源管理器进程,然后再从任务管理器重新启动它

一旦我这样做,我就可以从Windows资源管理器中生成的cmd访问新的环境变量。

答案 11 :(得分:5)

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

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

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

输出以幻数开头。因此,要使用find命令搜索它,需要对其进行输入和重定向:REGEDIT /E &lt;filename&gt; "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"

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

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

答案 12 :(得分:4)

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

答案 13 :(得分:4)

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

PATH=(VARIABLE);%path%

并按输入

检查你的变量是否已加载,输入

PATH

并按输入。但是,在重新引导之前,变量只是路径的一部分。

答案 14 :(得分:4)

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

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

taskkill /f /im explorer.exe && explorer.exe

答案 15 :(得分:3)

我在批处理脚本中使用以下代码:

if not defined MY_ENV_VAR (
    setx MY_ENV_VAR "VALUE" > nul
    set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%

SETX 之后使用 SET ,可以使用&#34; local&#34;直接变量而不重新启动命令窗口。在下一次运行中,将使用环境变量。

答案 16 :(得分:3)

只需重新启动explorer.exe&gt;&gt;在win 8 X64上测试

答案 17 :(得分:3)

我喜欢巧克力所遵循的方法,正如匿名懦夫的答案所述,因为它是纯粹的批量方法。但是,它会留下一个临时文件和一些临时变量。我为自己制作了一个更干净的版本。

refreshEnv.bat的某处创建一个PATH文件。通过执行refreshEnv来刷新控制台环境。

@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.

答案 18 :(得分:2)

如果您只需要在Windows中刷新环境变量,请从终端运行refreshenv而不是重新启动PC。

答案 19 :(得分:2)

首先安装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'))

然后您可以运行refreshenv。它可以在cmd和powershell上使用。

答案 20 :(得分:2)

如果它只涉及您想要更改的一个(或几个)特定变量,我认为最简单的方法是解决方法:只需在您的环境和当前控制台会话中设置

  • Set会将var放在当前会话中
  • SetX会将var放在环境中,但不会放在当前会话中

我有这个简单的批处理脚本将我的Maven从Java7更改为Java8(这两者都是env.vars)批处理文件夹位于我的 PATH var中,所以我总是可以调用' j8 '在我的控制台和环境中,我的JAVA_HOME var发生了变化:

<强> j8.bat:

@echo off
set JAVA_HOME=%JAVA_HOME_8%
setx JAVA_HOME "%JAVA_HOME_8%"

直到现在我发现这个工作最好,最简单。 您可能希望将其放在一个命令中,但它在Windows中根本不存在...

答案 21 :(得分:1)

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

@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

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

答案 22 :(得分:1)

感谢您发布这个非常有趣的问题,即使在2019年(实际上,更新shell cmd也并不容易,因为它是如上所述的单个实例),因为在Windows中更新环境变量可以完成很多工作自动化任务,而无需手动重新启动命令行。

例如,我们使用它来允许在我们定期重新安装的大量计算机上部署和配置软件。而且我必须承认,在部署软件期间必须重新启动命令行是非常不切实际的,并且将要求我们找到不一定令人满意的解决方法。 让我们解决我们的问题。 我们进行如下。

1-我们有一个批处理脚本,依次调用了这样的Powershell脚本

[文件:task.cmd]

cmd > powershell.exe -executionpolicy unrestricted -File C:\path_here\refresh.ps1

2-之后,refresh.ps1脚本使用注册表项(GetValueNames()等)更新环境变量。 然后,在相同的powershell脚本中,我们只需要调用可用的新环境变量即可。 例如,在典型情况下,如果我们之前使用无声命令在cmd上安装了nodeJS,则在调用该函数之后,我们可以直接调用npm在同一会话中安装以下特定软件包。

[文件:refresh.ps1]

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相同的命令。

答案 23 :(得分:1)

我使用此Powershell脚本添加到 PATH 变量。 稍微调整一下,我相信它也适用于你的情况。

#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%"

答案 24 :(得分:1)

正如凯夫所说,没有直接的方法。在大多数情况下,生成另一个CMD盒子更简单。更令人讨厌的是,正在运行的程序也不知道有任何变化(尽管IIRC可能会收到广播消息,要求通知此类更改)。

情况更糟:在旧版本的Windows中,您必须注销然后重新登录以考虑更改......

答案 25 :(得分:0)

不,我不这么认为......你可以手动设置它们。所以你可以将它们放在批处理文件中。

可能会创建一个实用程序/脚本(如果有人还没有)查询注册表并将当前环境设置为相同

答案 26 :(得分:0)

编辑:仅当运行批处理文件导致环境发生变化时才有效。

如果批处理文件以SETLOCAL开头,则即使您在批处理退出之前忘记调用ENDLOCAL,或者意外中止,也会在退出时将其解析回原始环境。

我写的几乎每个批处理文件都以SETLOCAL开头,因为在大多数情况下,我不希望保留环境变化的副作用。如果我确实希望某些环境变量更改在批处理文件之外传播,那么我的上一个ENDLOCAL看起来像这样:

ENDLOCAL & (
  SET RESULT1=%RESULT1%
  SET RESULT2=%RESULT2%
)

答案 27 :(得分:-1)

为了解决这个问题,我使用BOTH setx和set更改了环境变量,然后重新启动了explorer.exe的所有实例。这样,随后启动的任何进程都将具有新的环境变量。

我的批处理脚本执行此操作:

setx /M ENVVAR "NEWVALUE"
set ENVVAR="NEWVALUE"

taskkill /f /IM explorer.exe
start explorer.exe >nul
exit

这种方法的问题是当前打开的所有资源管理器窗口都将关闭,这可能是一个坏主意 - 但请参阅Kev的帖子,了解为什么这是必要的

答案 28 :(得分:-2)

或者你可以通过

手动完成
  

要查看或更改环境变量:右键单击“我的电脑”,然后单击“确定”   然后单击属性。单击“高级”选项卡。单击环境   变量。对于用户或a,单击以下选项之一   系统变量:单击“新建”以添加新变量名称和值。点击   现有变量,然后单击“编辑”以更改其名称或值。   单击现有变量,然后单击“删除”将其删除。    http://support.microsoft.com/kb/310519

Windows XP环境变量

%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环境变量

%ALLUSERSPROFILE% (%PROGRAMDATA%)   C:\ProgramData
%APPDATA%   C:\Users\{username}\AppData\Roaming
%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\

http://www.binbert.com/blog/2010/09/default-environment-variable-values-of-windows-7-xp/

希望这会有所帮助。

答案 29 :(得分:-3)

只需在终端中键入“#-r”(不带引号#with -r选项)。 而且你们都被设置为默认路径:)