환경 변수를 수정하거나 추가하면 명령 프롬프트를 다시 시작해야합니다. CMD를 다시 시작하지 않고 실행할 수있는 명령이 있습니까?
환경 변수를 수정하거나 추가하면 명령 프롬프트를 다시 시작해야합니다. 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 + 임시 박쥐 메커니즘을 사용하여 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"
여기 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 .
RefreshEnv
현재 세션에 업데이트 된 환경 변수를 가져 오기 위해 실행할 수 있습니다 .
Powershell
합니까? 그것은 cmd.exe
나를 위해 일하는 것 같습니다 .
Windows 7/8/10에서는이 기본 제공 스크립트가있는 Chocolatey를 설치할 수 있습니다.
Chocolatey를 설치 한 후을 입력하십시오 refreshenv
.
디자인에 의해 내장되어 있지 않습니다 으로 다른 cmd.exe 또는 "내 컴퓨터-> 속성-> 고급 설정->에서 이미 실행중인 cmd.exe에 환경 변수 추가 / 변경 / 제거를 전달하는 Windows 용 메커니즘 환경 변수".
기존의 열린 명령 프롬프트 범위 밖에서 새 환경 변수를 수정하거나 추가하는 경우 명령 프롬프트를 다시 시작하거나 기존 명령 프롬프트에서 SET을 사용하여 수동으로 추가해야합니다.
가장 최근에 승인 된 답변 은 스크립트에서 모든 환경 변수를 수동으로 새로 고침하여 부분적인 해결 방법을 보여줍니다 . 이 스크립트는 "내 컴퓨터 ... 환경 변수"에서 환경 변수를 전역으로 변경하는 유스 케이스를 처리하지만 한 cmd.exe에서 환경 변수가 변경되면 스크립트는이를 실행중인 다른 cmd.exe로 전파하지 않습니다.
나는 더 쉬운 해결책을 찾기 전에이 대답을 보았습니다.
explorer.exe
작업 관리자에서 다시 시작하면 됩니다.
테스트하지는 않았지만 명령 프롬프트를 다시 열어야 할 수도 있습니다.
Timo Huovinen의 크레디트 : 노드가 성공적으로 설치되었지만 인식되지 않습니다 .
cmd
관리자 권한으로 창을 시작하십시오 . 명령을 사용하십시오 taskkill /f /im explorer.exe && explorer.exe
. explorer.exe 프로세스가 종료되고 다시 시작됩니다.
이것은 Windows 7에서 작동합니다. SET PATH=%PATH%;C:\CmdShortcuts
echo % PATH %를 입력하여 테스트했는데 정상적으로 작동했습니다. 새 cmd를 열면 더 이상 성가신 재부팅 할 필요가 없습니다. :)
setx
그것이 영구적으로 원하는 것이 아니라 수정 된 변수를 가질 수있는 현재 환경을 상속하기 때문에 사용하는 것을 좋아하지 않습니다 . 이 방법을 사용하면 변수를 사용하기 위해 콘솔을 다시 시작하지 않아도되며 향후 전역에서 사용할 수없는 문제를 피할 수 있습니다.
"setx"를 사용하고 cmd 프롬프트를 재시작하십시오
이 작업 에는 " setx " 라는 명령 행 도구가 있습니다 . env 변수 를 읽고 쓰는 데 사용 됩니다. 변수는 명령 창이 닫힌 후에도 유지됩니다.
"프로그래밍이나 스크립팅없이 사용자 또는 시스템 환경에서 환경 변수를 작성하거나 수정합니다. setx 명령은 레지스트리 키의 값을 검색하여 텍스트 파일에 씁니다."
참고 :이 도구로 만들거나 수정 한 변수는 향후 명령 창에서 사용할 수 있지만 현재 CMD.exe 명령 창에서는 사용할 수 없습니다. 따라서 다시 시작해야합니다.
setx
누락 된 경우 :
또는 레지스트리를 수정하십시오.
MSDN의 말 :
시스템 환경 변수를 프로그래밍 방식으로 추가하거나 수정하려면 HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment 레지스트리 키에 변수를 추가 한 다음 lParam 을 문자열 " Environment "로 설정하여 WM_SETTINGCHANGE 메시지 를 브로드 캐스트하십시오 .
이를 통해 셸과 같은 응용 프로그램에서 업데이트를 선택할 수 있습니다.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE
현재 사용자 환경 : HKEY_CURRENT_USER\Environment\VARIABLE
%PATH%
후 setx
1024 바이트이를자를 수 있습니다! 그와 마찬가지로 그의 저녁은 사라졌습니다
이 함수를 호출하면 나를 위해 일했습니다 :
VOID Win32ForceSettingsChange()
{
DWORD dwReturnValue;
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
내가 생각해 낸 가장 좋은 방법은 레지스트리 쿼리를 수행하는 것입니다. 여기 내 예가 있습니다.
내 예제에서는 새로운 환경 변수를 추가 한 배치 파일을 사용하여 설치를 수행했습니다. 설치가 완료 되 자마자이 작업을 수행해야했지만 새 변수로 새 프로세스를 생성 할 수 없었습니다. 다른 탐색기 창을 생성하고 다시 cmd.exe로 다시 호출 한 결과 이것이 작동했지만 Vista와 Windows 7에서는 탐색기가 단일 인스턴스로만 실행되며 일반적으로 로그인 한 사람 만 실행됩니다. 로컬 시스템에서 실행하거나 상자에서 관리자로 실행하는 것과 상관없이 작업을 수행하십시오. 이것의 한계는 경로와 같은 것을 처리하지 않는다는 것입니다. 이것은 단순한 환경 변수에서만 작동했습니다. 이것은 배치를 사용하여 (공백이있는) 디렉토리로 가져 와서 .exe 등을 실행하는 파일로 복사 할 수있게했습니다.
원래 배치는 새 배치를 호출합니다.
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
현재 세션을 재부팅하지 않고 경로에 변수를 추가하는 가장 쉬운 방법은 명령 프롬프트를 열고 다음을 입력하는 것입니다.
PATH=(VARIABLE);%path%
그리고 누르십시오 enter .
변수가로드되었는지 확인하려면 다음을 입력하십시오.
PATH
를 누릅니다 enter. 그러나 재부팅 할 때까지 변수는 경로의 일부일뿐입니다.
지정된 프로세스 자체 내에서 환경 테이블을 겹쳐 써서이를 수행 할 수 있습니다.
개념 증명으로이 샘플 앱을 작성했는데 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의 답변으로 문서화 됨)를 열거하고 전체 환경 테이블을 대상 프로세스의 메모리에 씁니다.
편집 : 환경 블록의 크기도 _RTL_USER_PROCESS_PARAMETERS 구조체에 저장되지만 메모리는 프로세스의 힙에 할당됩니다. 따라서 외부 프로세스에서는 크기를 조정하고 더 크게 만들 수 없습니다. 환경 저장소의 대상 프로세스에서 추가 메모리를 할당하기 위해 VirtualAllocEx를 사용하여 놀았으며 완전히 새로운 테이블을 설정하고 읽을 수있었습니다. 불행히도 정상적인 방법으로 환경을 수정하려는 시도는 주소가 더 이상 힙을 가리 키지 않기 때문에 충돌하고 타 버립니다 (RtlSizeHeap에서 충돌 함).
환경 변수는 HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Session Manager \ Environment에 유지됩니다.
Path와 같은 유용한 환경 변수는 REG_SZ로 저장됩니다. REGEDIT를 포함하여 레지스트리에 액세스하는 몇 가지 방법이 있습니다.
REGEDIT /E <filename> "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"
출력은 매직 넘버로 시작합니다. 따라서 find 명령으로 검색하려면 입력하고 경로를 재지 정해야합니다.type <filename> | findstr -c:\"Path\"
따라서 시스템 속성의 내용으로 현재 명령 세션에서 경로 변수를 새로 고치려면 다음 배치 스크립트가 올바르게 작동합니다.
RefreshPath.cmd :
@ 에코 오프 REM이 솔루션은 레지스트리에서 읽기 위해 권한 상승을 요청합니다. 존재하는 경우 % temp % \ env.reg del % temp % \ env.reg / q / f REGEDIT / E % temp % \ env.reg "HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Session Manager \ 환경" 존재하지 않는 경우 % temp % \ env.reg ( echo "임시 위치에 레지스트리를 쓸 수 없습니다" 1 번 출구 ) SETLOCAL EnableDelayedExpansion / f "tokens = 1,2 * delims =="%% i in ( 'type % temp % \ env.reg ^ | findstr -c : \ "Path \"=') upath = %% ~ j로 설정 echo! upath : \\ = \! > % temp % \ newpath ) 내향 / f "tokens = *"에 대해 (% temp % \ newpath)의 %% i는 path = %% i를 설정합니다.
혼란스러운 것은 cmd를 시작할 곳이 몇 군데있을 수 있습니다. 내 경우에는 내가 도망 탐색기 창에서 cmd를 하고 환경 변경하지 않은 변수를 시작할 때 상태 "실행"에서 cmd를 환경 (윈도우 키 + r)을 변수 변경되었습니다 .
내 경우에는 방금 작업 관리자에서 Windows 탐색기 프로세스를 종료 한 다음 작업 관리자에서 다시 시작해야했습니다 .
일단 이것을하면 Windows 탐색기에서 생성 된 cmd에서 새 환경 변수에 액세스 할 수있었습니다.
배치 스크립트에서 다음 코드를 사용합니다.
if not defined MY_ENV_VAR (
setx MY_ENV_VAR "VALUE" > nul
set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%
사용하여 SET를 한 후 SETX 는 명령 창을 다시 시작하지 않고 직접 "로컬"변수를 사용하는 것이 가능하다. 그리고 다음 번에는 환경 변수가 사용됩니다.
익명의 겁쟁이의 답변에 게시 된 것처럼 순결한 배치 방식이므로 접근법과 초콜릿을 좋아했습니다. 그러나 임시 파일과 일부 임시 변수가 남아 있습니다. 나는 더 깨끗한 버전을 만들었습니다.
에 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.
변경하려는 특정 변수 중 하나 (또는 몇 가지)에만 관심이 있다면 가장 쉬운 방법은 해결 방법이라고 생각 합니다. 환경과 현재 콘솔 세션에서 설정하십시오.
이 간단한 배치 스크립트를 사용하여 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에는 단순히 존재하지 않습니다 ...
몇 년 동안 사용해온 솔루션은 다음과 같습니다.
@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
편집 : 웁스, 여기 업데이트 된 버전이 있습니다.
이 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%"
Windows에서도 환경 변수를 갱신하면 많은 자동화 작업을 수행 할 수 있기 때문에 2019 년에도 매우 흥미로운이 질문을 게시 해 주셔서 감사합니다 (실제로 위에서 언급 한 단일 인스턴스이므로 쉘 cmd를 갱신하는 것은 쉽지 않습니다) 명령 줄을 수동으로 다시 시작해야합니다.
예를 들어,이 소프트웨어를 사용하여 정기적으로 재설치하는 많은 컴퓨터에 소프트웨어를 배포하고 구성 할 수 있습니다. 또한 소프트웨어를 배포하는 동안 명령 줄을 다시 시작해야하는 것은 매우 비현실적이며 반드시 유쾌하지 않은 해결 방법을 찾아야한다는 점을 인정해야합니다. 우리 문제에 갑시다. 다음과 같이 진행합니다.
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와 동일한 명령을 호출 할 수 있습니다.
편집 : 이것은 환경 변경이 배치 파일을 실행 한 결과 인 경우에만 작동합니다.
배치 파일로 시작 SETLOCAL
하면 전화를 잊어 버려도 종료시 항상 원래 환경으로 되돌아갑니다.ENDLOCAL
되면 배치가 종료되기 전에 거나 예기치 않게 중단 된 경우 .
필자가 작성하는 거의 모든 배치 파일 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의 게시물을 참조하여 이것이 필요한 이유를 알아보십시오