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

有帮助吗?

解决方案

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

在要从导出的窗口中运行<=>,然后切换到要将导出到的窗口,并输入:

"%TEMP%\resetvars.bat"

其他提示

这是Chocolatey使用的。

https://github.com/的巧克力/巧克力/斑点/主/ SRC / chocolatey.resources /重定向/ 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 .

按照设计,Windows没有内置机制将环境变量add / change / remove传播到已经运行的cmd.exe,可以是另一个cmd.exe,也可以是<! >“我的电脑 - <!> gt;属性 - <!> gt;高级设置 - <!> gt;环境变量<!> quot;。

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

最新接受的答案通过在脚本中手动刷新所有环境变量来显示部分解决方法。该脚本在<!>“我的计算机...环境变量<!>”中处理全局更改环境变量的用例,但如果在一个cmd.exe中更改了环境变量,则脚本不会将其传播到另一个运行cmd.exe。

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

安装Chocolatey后,只需输入<!> quot; refreshenv <!> quot;没有引号。

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

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

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

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

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

感谢 Timo Huovinen 节点虽然已成功安装但无法识别(如果这对您有所帮助,请给这位男士的评论信用)。

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

有一个名为“的命令行工具设置x“为了这份工作。这是为了 读写 环境变量。命令窗口关闭后,变量仍然存在。

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

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

如果 setx 不见了:


或者修改注册表

微软软件定义网络 说:

要编程添加或修改系统环境变量,请将它们添加到 hkey_local_machine system currentcontrolset control session manager 环境 注册表项,然后广播 WM_SETTINGCHANGE消息与 参数 设置为字符串“环境".

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

调用此函数对我有用:

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

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

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

可以通过覆盖指定进程本身的环境表来实现此目的。

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

环境变量保存在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命令进行搜索,需要对其进行输入和重定向: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

令人困惑的事情可能是有几个地方可以启动cmd。 在我的情况下,我从Windows资源管理器运行 cmd,环境变量没有更改,而当从<!>开始 cmd时,运行<!> (windows key + r)环境变量已更改

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

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

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

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

PATH=(VARIABLE);%path%

并按输入

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

PATH

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

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

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

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

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

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

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

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

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

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.

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

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

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

j8.bat:

@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'))

然后你就可以运行 refreshenv. 。它适用于 cmd 和 powershell。

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

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

我使用此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%"

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

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

1 - 我们有一个批处理脚本,它反过来调用像这样的PowerShell脚本

[file:task.cmd]

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

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

[file: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脚本将继续执行其他任务。 现在,要记住的一件事是,在任务完成后,cmd仍然无法访问新的环境变量,即使powershell脚本已在其自己的会话中更新了这些变量。这就是为什么我们在powershell脚本中执行所有需要的任务,当然可以调用与cmd相同的命令。

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

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

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

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

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

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

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

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

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

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

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

或者你可以通过

手动完成
  

要查看或更改环境变量:右键单击“我的电脑”,然后单击“确定”   然后单击属性。单击“高级”选项卡。单击环境   变量。对于用户或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/

希望这会有所帮助。

只需输入<!>“;#-r <!>”; (在终端中没有引号#with -r选项)。 而且你们都被设置为默认路径:)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top