Есть ли команда для обновления переменных среды из командной строки в Windows?

StackOverflow https://stackoverflow.com/questions/171588

Вопрос

Если я изменяю или добавляю переменную среды, мне придется перезапустить командную строку.Есть ли команда, которую я мог бы выполнить, чтобы сделать это без перезапуска 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


Апологетика:

Две основные проблемы, с которыми я столкнулся при этом решении, заключались в следующем:

а. Я не смог найти простой способ экспортировать переменные среды из сценария VBS обратно в командную строку, и

б. переменная среды PATH представляет собой объединение пользовательской и системной переменных PATH.

Я не уверен, каково общее правило для конфликта переменных между пользователем и системой, поэтому я решил сделать так, чтобы пользователь переопределял систему, за исключением переменной PATH, которая обрабатывается особым образом.

Я использую странный механизм vbs+bat+temporary bat, чтобы обойти проблему экспорта переменных из vbs.

Примечание:этот скрипт не удаляет переменные.

Вероятно, это можно улучшить.

ДОБАВЛЕН

Если вам нужно экспортировать среду из одного окна 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"

Другие советы

Вот что использует 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; Переменные среды & Quot;.

Если вы изменяете или добавляете новую переменную среды вне области существующей открытой командной строки, вам необходимо либо перезапустить командную строку, либо добавить вручную, используя SET в существующей командной строке.

последний принятый ответ показывает частичное решение, вручную обновляя все переменные среды в скрипте. Сценарий обрабатывает сценарий изменения глобальных переменных среды в & Quot; Мой компьютер ... Переменные среды & Quot;, но если переменная среды изменяется в одном cmd.exe, сценарий не будет распространять его на другой работает cmd.exe.

В Windows 7/8/10 вы можете установить Chocolatey, в котором есть встроенный скрипт.

После установки Chocolatey просто введите " refreshenv " без кавычек.

Это работает в Windows 7: SET PATH=%PATH%;C:\CmdShortcuts

проверил, набрав echo% PATH%, и все заработало. также установите, если вы открываете новый cmd, вам больше не нужны эти надоедливые перезагрузки:)

Я наткнулся на этот ответ, прежде чем в конце концов нашел более простое решение.

Просто перезапустите explorer.exe в диспетчере задач.

Я не тестировал, но вам также может потребоваться повторно открыть командную строку.

Сообщите Тимо Хуовинен здесь: Узел не распознан, хотя и успешно установлен (если это помогло вам, перейдите, пожалуйста, оставьте комментарий этого человека).

Используйте «setx» и перезапустите командную строку cmd.

Существует инструмент командной строки под названием «setx"на эту работу.Это для чтение и запись переменные окружения.Переменные сохраняются после закрытия командного окна.

Он «Создает или изменяет переменные среды в пользовательской или системной среде без необходимости программирования или написания сценариев.А setx Команда также извлекает значения ключей реестра и записывает их в текстовые файлы».

Примечание:переменные, созданные или измененные с помощью этого инструмента, будут доступны в будущих командных окнах, но не в текущем командном окне CMD.exe.Итак, вам придется перезапустить.

Если setx пропал, отсутствует:


Или изменить реестр

MSDN говорит:

Чтобы программно добавить или изменить переменные системной среды, добавьте их в Hkey_local_machine System CurrentControlSet Control Session Manager Environment ключ реестра, затем транслируйте WM_SETTINGCHANGEсообщение с лПарам установить строку "Среда".

Это позволяет приложениям, таким как оболочка, получать ваши обновления.

Вызов этой функции помог мне:

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

Лучший способ, с которым я пришел, - это просто сделать запрос в реестре. Вот мой пример.

В моем примере я установил пакетный файл, в который были добавлены новые переменные среды. Мне нужно было что-то сделать с этим, как только установка была завершена, но я не смог запустить новый процесс с этими новыми переменными. Я протестировал создание другого окна обозревателя и перезвонил cmd.exe, и это сработало, но в Vista и Windows 7 проводник запускается только как один экземпляр и обычно как пользователь, вошедший в систему. Это не получится при автоматизации, так как мне нужны права администратора для делать вещи независимо от запуска из локальной системы или от имени администратора на поле. Ограничением является то, что он не обрабатывает такие вещи, как путь, это работает только для простых переменных окружения. Это позволило мне использовать пакет для перехода в каталог (с пробелами) и копирования в файлы, запускаемые .exes и т. Д. Это было написано сегодня из майских ресурсов на stackoverflow.com

Оригинальные пакетные вызовы новой партии:

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 _PEB и dt _RTL_USER_PROCESS_PARAMETERS)

Чтобы преобразовать концептуальное доказательство в то, что нужно OP, нужно просто перечислить переменные текущей системы и среды пользователя (например, задокументированные в ответе @ tsadok) и записать всю таблицу среды в память целевого процесса. .

Edit: Размер блока среды также сохраняется в структуре _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\"

Итак, если вы просто хотите обновить переменную пути в текущем командном сеансе с тем, что указано в свойствах системы, следующий пакетный скрипт работает нормально:

ОбновитьПат.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. В моем случае я запустил cmd из проводника Windows , и переменные среды не изменились , а при запуске cmd из & Quot; run & Quot; (windows key + r) переменные среды были изменены .

В моем случае мне просто пришлось убить процесс проводника Windows из диспетчера задач, а затем снова запустить его из диспетчера задач .

После этого я получил доступ к новой переменной среды из cmd, который был создан из проводника Windows.

Попробуйте открыть новую командную строку от имени администратора. Это работало для меня в 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%

Используя SET после SETX , можно использовать " local " Переменная напрямую без перезапуска командного окна. И при следующем запуске будет использоваться переменная окружения.

просто перезапустите explorer.exe > > проверено на 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 поместит переменную в ваш текущий сеанс.
  • SetX поместит переменную в среду, но НЕ в ваш текущий сеанс.

У меня есть простой пакетный скрипт для изменения моего Maven с Java7 на Java8 (оба являются env.vars) Пакетная папка находится в моем ПУТЬ var, чтобы я всегда мог позвонить 'j8' и в моей консоли и в среде моя переменная JAVA_HOME изменяется:

j8.бат:

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

До сих пор я считаю, что это работает лучше всего и проще всего.Вероятно, вы хотите, чтобы это было в одной команде, но в Windows этого просто нет...

Сначала установите шоколад:

  • если использовать 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 году (действительно, обновить командную оболочку нелегко, так как это единственный экземпляр, как упомянуто выше), потому что обновление переменных среды в окнах позволяет выполнять многие задачи автоматизации без необходимости перезапуска командной строки вручную.

Например, мы используем это для обеспечения возможности развертывания и настройки программного обеспечения на большом количестве машин, которые мы регулярно переустанавливаем. И я должен признать, что перезапуск командной строки во время развертывания нашего программного обеспечения был бы очень непрактичным и потребовал бы от нас найти обходные пути, которые не обязательно приятны. Давайте вернемся к нашей проблеме. Мы действуем следующим образом.

1 - у нас есть пакетный скрипт, который в свою очередь вызывает скрипт powershell, подобный этому

[file: task.cmd] .

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

2 - После этого сценарий refresh.ps1 обновляет переменные среды, используя ключи реестра (GetValueNames () и т. д.). Затем в том же скрипте powershell нам просто нужно вызвать новые переменные среды. Например, в типичном случае, если мы только что установили nodeJS ранее с помощью cmd с использованием тихих команд, после вызова функции мы можем напрямую вызвать 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%
)

Чтобы решить эту проблему, я изменил переменную среды, используя ОБА setx и set, а затем перезапустил все экземпляры explorer.exe. Таким образом, любой процесс, запущенный впоследствии, будет иметь новую переменную среды.

Мой пакетный скрипт для этого:

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

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

Проблема этого подхода заключается в том, что все окна проводника, которые открыты в данный момент, будут закрыты, что, вероятно, является плохой идеей. Но посмотрите статью Кева, чтобы узнать, почему это необходимо

Или вы можете просто сделать это вручную через

  

Чтобы просмотреть или изменить переменные среды: щелкните правой кнопкой мыши Мой компьютер и   затем нажмите Свойства. Перейдите на вкладку «Дополнительно». Нажмите Среда   переменные. Выберите один из следующих вариантов, для пользователя или   системная переменная: нажмите New, чтобы добавить имя и значение новой переменной. Нажмите   существующей переменной, а затем нажмите кнопку «Изменить», чтобы изменить ее имя или значение.   Щелкните существующую переменную, а затем нажмите «Удалить», чтобы удалить ее.    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 " (без кавычек # с опцией -r) в вашем терминале. И вы все настроены на пути по умолчанию:)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top