Nếu tôi sửa đổi hoặc thêm một biến môi trường, tôi phải khởi động lại dấu nhắc lệnh. Có một lệnh tôi có thể thực thi sẽ làm điều này mà không cần khởi động lại CMD?
Nếu tôi sửa đổi hoặc thêm một biến môi trường, tôi phải khởi động lại dấu nhắc lệnh. Có một lệnh tôi có thể thực thi sẽ làm điều này mà không cần khởi động lại CMD?
Câu trả lời:
Bạn có thể nắm bắt các biến môi trường hệ thống bằng tập lệnh vbs, nhưng bạn cần một tập lệnh bat để thực sự thay đổi các biến môi trường hiện tại, vì vậy đây là một giải pháp kết hợp.
Tạo một tệp có tên resetvars.vbs
chứa mã này và lưu nó trên đường dẫn:
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
tạo một tên tệp resetvars.bat có chứa mã này, cùng một vị trí:
@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"
Khi bạn muốn làm mới các biến môi trường, chỉ cần chạy resetvars.bat
Lời xin lỗi :
Hai vấn đề chính tôi gặp phải với giải pháp này là
a. Tôi không thể tìm thấy một cách đơn giản để xuất các biến môi trường từ tập lệnh vbs trở lại dấu nhắc lệnh và
b. biến môi trường PATH là sự kết hợp của người dùng và các biến PATH của hệ thống.
Tôi không chắc quy tắc chung là gì đối với các biến xung đột giữa người dùng và hệ thống, vì vậy tôi đã chọn để tạo hệ thống ghi đè người dùng, ngoại trừ trong biến PATH được xử lý cụ thể.
Tôi sử dụng cơ chế lạ vbs + bat + bat để giải quyết vấn đề xuất biến từ vbs.
Lưu ý : tập lệnh này không xóa các biến.
Điều này có thể được cải thiện.
THÊM
Nếu bạn cần xuất môi trường từ cửa sổ cmd này sang cửa sổ khác, hãy sử dụng tập lệnh này (hãy gọi nó là 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
Chạy exportvars.vbs
trong cửa sổ bạn muốn xuất khẩu từ , sau đó chuyển sang cửa sổ bạn muốn xuất khẩu tới , và gõ:
"%TEMP%\resetvars.bat"
Đây là những gì Chocolatey sử dụng.
https://github.com/chocolatey/choco/blob/master/src/chocolatey.resource/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
để nhận các biến môi trường được cập nhật vào phiên hiện tại của bạn.
Powershell
quá không? Nó dường như chỉ làm việc cmd.exe
cho tôi.
Trên Windows 7/8/10, bạn có thể cài đặt Chocolatey, có tập lệnh cho tích hợp này.
Sau khi cài đặt Chocolatey, chỉ cần gõ refreshenv
.
Theo thiết kế có không phải là một xây dựng trong cơ chế cho Windows để tuyên truyền một biến môi trường thêm / thay đổi / remove một cmd.exe đang chạy, hoặc từ cmd.exe khác hoặc từ "My Computer -> Properties -> Advanced Settings -> Biến môi trường ".
Nếu bạn sửa đổi hoặc thêm một biến môi trường mới bên ngoài phạm vi của dấu nhắc lệnh mở hiện có, bạn cần phải khởi động lại dấu nhắc lệnh hoặc thêm thủ công bằng cách sử dụng SET trong dấu nhắc lệnh hiện có.
Các mới nhất Câu trả lời được chấp nhận chương trình một công việc xung quanh một phần bằng cách thủ công làm mới tất cả các biến môi trường trong một kịch bản. Tập lệnh xử lý trường hợp sử dụng thay đổi các biến môi trường trên toàn cầu trong "Máy tính của tôi ... Biến môi trường", nhưng nếu một biến môi trường được thay đổi trong một cmd.exe, tập lệnh sẽ không truyền nó sang một cmd.exe khác đang chạy.
Tôi đã xem qua câu trả lời này trước khi tìm ra giải pháp dễ dàng hơn.
Chỉ cần khởi động lại explorer.exe
trong Trình quản lý tác vụ.
Tôi đã không kiểm tra, nhưng bạn cũng có thể cần phải mở lại dấu nhắc lệnh.
Tín dụng cho Timo Huovinen tại đây: Nút không được công nhận mặc dù đã được cài đặt thành công (nếu điều này giúp bạn, vui lòng gửi tín dụng nhận xét của người đàn ông này).
cmd
cửa sổ với tư cách Quản trị viên. Sử dụng lệnh taskkill /f /im explorer.exe && explorer.exe
. Điều này sẽ giết quá trình explorer.exe và khởi động lại nó.
Điều này hoạt động trên windows 7: SET PATH=%PATH%;C:\CmdShortcuts
đã kiểm tra bằng cách gõ echo% PATH% và nó hoạt động tốt. cũng thiết lập nếu bạn mở một cmd mới, không cần những lần khởi động lại phiền phức nữa :)
setx
vì nó kế thừa môi trường hiện tại có thể có các biến đã được sửa đổi và không phải là thứ tôi muốn vĩnh viễn. Làm theo cách này cho phép tôi tránh khởi động lại bàn điều khiển để sử dụng các biến, đồng thời tránh vấn đề không có sẵn chúng trên toàn cầu trong tương lai.
Sử dụng "setx" và khởi động lại dấu nhắc cmd
Có một công cụ dòng lệnh có tên là " setx " cho công việc này. Nó để đọc và viết các biến env. Các biến vẫn tồn tại sau khi cửa sổ lệnh đã được đóng.
Nó "Tạo hoặc sửa đổi các biến môi trường trong môi trường người dùng hoặc hệ thống, mà không yêu cầu lập trình hoặc tập lệnh. Lệnh setx cũng lấy các giá trị của các khóa đăng ký và ghi chúng vào tệp văn bản."
Lưu ý: các biến được tạo hoặc sửa đổi bởi công cụ này sẽ có sẵn trong các cửa sổ lệnh trong tương lai nhưng không có trong cửa sổ lệnh CMD.exe hiện tại. Vì vậy, bạn phải khởi động lại.
Nếu setx
bị thiếu:
Hoặc sửa đổi sổ đăng ký
MSDN nói:
Để lập trình thêm hoặc sửa đổi các biến môi trường hệ thống, hãy thêm chúng vào HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ môi trường khóa, sau đó phát thông báo WM_SettINGCHANGE với lParam được đặt thành chuỗi " Môi trường ".
Điều này cho phép các ứng dụng, chẳng hạn như trình bao, nhận các bản cập nhật của bạn.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE
người dùng hiện tại: HKEY_CURRENT_USER\Environment\VARIABLE
%PATH%
thì setx
có thể cắt nó thành 1024 byte! Và cứ như thế, buổi tối của anh biến mất
Gọi chức năng này đã làm việc cho tôi:
VOID Win32ForceSettingsChange()
{
DWORD dwReturnValue;
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
Phương pháp tốt nhất tôi nghĩ ra là chỉ cần thực hiện một truy vấn Registry. Đây là ví dụ của tôi.
Trong ví dụ của tôi, tôi đã cài đặt bằng tệp Batch có thêm các biến môi trường mới. Tôi cần phải thực hiện mọi thứ với điều này ngay khi cài đặt hoàn tất, nhưng không thể tạo ra một quy trình mới với các biến mới đó. Tôi đã thử nghiệm sinh ra một cửa sổ thám hiểm khác và gọi lại cho cmd.exe và điều này đã hoạt động nhưng trên Vista và Windows 7, Explorer chỉ chạy như một phiên bản duy nhất và thông thường là người đăng nhập. Điều này sẽ thất bại với tự động hóa vì tôi cần quản trị viên của mình làm mọi việc bất kể chạy từ hệ thống cục bộ hoặc là quản trị viên trên hộp. Hạn chế của điều này là nó không xử lý những thứ như đường dẫn, điều này chỉ hoạt động trên các biến môi trường đơn giản. Điều này cho phép tôi sử dụng một lô để truy cập vào một thư mục (có dấu cách) và sao chép trong các tệp chạy .exes, v.v. Điều này được viết ngày hôm nay từ tài nguyên có thể trên stackoverflow.com
Orginal Batch gọi tới Batch mới:
testenvget.cmd SDROOT (hoặc bất cứ biến nào)
@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
Ngoài ra có một phương pháp khác mà tôi đã đưa ra từ nhiều ý tưởng khác nhau. Vui lòng xem bên dưới. Về cơ bản, điều này sẽ nhận được biến đường dẫn mới nhất từ sổ đăng ký, tuy nhiên, điều này sẽ gây ra một số vấn đề khi sử dụng truy vấn đăng ký sẽ tự đưa ra các biến, điều đó có nghĩa là ở đâu cũng có một biến này sẽ không hoạt động, vì vậy để chống lại vấn đề này về cơ bản tăng gấp đôi đường dẫn. Rất khó chịu. Phương pháp được quan tâm nhiều hơn sẽ được thực hiện: Đặt Đường dẫn =% Đường dẫn%; C: \ Chương trình Tệp \ Phần mềm .... \
Bất kể ở đây là tập tin lô mới, xin vui lòng sử dụng thận trọng.
@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
Cách dễ nhất để thêm một biến vào đường dẫn mà không cần khởi động lại cho phiên hiện tại là mở dấu nhắc lệnh và gõ:
PATH=(VARIABLE);%path%
và nhấn enter.
để kiểm tra xem biến của bạn đã được tải chưa, gõ
PATH
và nhấn enter. Tuy nhiên, biến sẽ chỉ là một phần của đường dẫn cho đến khi bạn khởi động lại.
Có thể thực hiện việc này bằng cách ghi đè Bảng Môi trường trong một quy trình được chỉ định.
Để chứng minh khái niệm, tôi đã viết ứng dụng mẫu này, nó chỉ chỉnh sửa một biến môi trường (đã biết) trong quy trình 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;
}
Đầu ra mẫu:
>set ENVTEST=abc
>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528
>set ENVTEST
ENVTEST=def
Cách tiếp cận này cũng sẽ được giới hạn trong các hạn chế bảo mật. Nếu mục tiêu được chạy ở độ cao cao hơn hoặc tài khoản cao hơn (chẳng hạn như HỆ THỐNG) thì chúng tôi sẽ không được phép chỉnh sửa bộ nhớ của nó.
Nếu bạn muốn thực hiện điều này với ứng dụng 32 bit, phần bù được mã hóa cứng ở trên sẽ thay đổi thành 0x10 và 0x48 tương ứng. Có thể tìm thấy các độ lệch này bằng cách loại bỏ _PEB và _RTL_USER_PROCESS_PARAMETERS trong trình gỡ lỗi (ví dụ: trong WinDbg dt _PEB
và dt _RTL_USER_PROCESS_PARAMETERS
)
Để thay đổi khái niệm bằng chứng thành những gì OP cần, nó sẽ chỉ liệt kê các biến môi trường người dùng và hệ thống hiện tại (như tài liệu của câu trả lời của @ tsadok) và ghi toàn bộ bảng môi trường vào bộ nhớ của quá trình đích.
Chỉnh sửa: Kích thước của khối môi trường cũng được lưu trữ trong cấu trúc _RTL_USER_PROCESS_PARAMETERS, nhưng bộ nhớ được phân bổ trên heap của tiến trình. Vì vậy, từ quy trình bên ngoài, chúng tôi sẽ không có khả năng thay đổi kích thước và làm cho nó lớn hơn. Tôi đã chơi xung quanh với việc sử dụng VirtualAllocEx để phân bổ bộ nhớ bổ sung trong quy trình đích cho bộ lưu trữ môi trường và có thể đặt và đọc một bảng hoàn toàn mới. Thật không may, bất kỳ nỗ lực nào để sửa đổi môi trường từ các phương tiện thông thường sẽ bị sập và cháy do địa chỉ không còn trỏ đến heap (nó sẽ bị sập trong RtlSizeHeap).
Các biến môi trường được giữ trong HKEY_LOCAL_MACHINE \ HỆ THỐNG \ ControlSet \ Control \ Trình quản lý phiên \ Môi trường.
Nhiều vars env hữu ích, chẳng hạn như Path, được lưu trữ dưới dạng REG_SZ. Có một số cách để truy cập vào sổ đăng ký, bao gồm cả REGEDIT:
REGEDIT /E <filename> "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"
Đầu ra bắt đầu với số ma thuật. Vì vậy, để tìm kiếm nó bằng lệnh find, nó cần được gõ và chuyển hướng:type <filename> | findstr -c:\"Path\"
Vì vậy, nếu bạn chỉ muốn làm mới biến đường dẫn trong phiên lệnh hiện tại của mình với thuộc tính hệ thống thì tập lệnh bó sau hoạt động tốt:
Làm mớiPath.cmd:
@echo tắt REM Giải pháp này yêu cầu độ cao để đọc từ sổ đăng ký. nếu tồn tại% temp% \ env.reg del% temp% \ env.reg / q / f REGEDIT / E% temp% \ env.reg "HKEY_LOCAL_MACHINE \ HỆ THỐNG \ ControlSet001 \ Control \ Trình quản lý phiên \ Môi trường" nếu không tồn tại% temp% \ env.reg ( echo "Không thể ghi registry vào vị trí tạm thời" thoát 1 ) SETLOCAL EnableDelayedExpansion for / f "tokens = 1,2 * delims ==" %% i in ('gõ% temp% \ env.reg ^ | findstr -c: \ "Path \" =') do ( thiết lập upath = %% ~ j echo! upath: \\ = \! >% tạm thời% \ newpath ) KẾT THÚC for / f "tokens = *" %% i trong (% temp% \ newpath) thực hiện đặt đường dẫn = %% i
Điều khó hiểu có thể là có một vài nơi để bắt đầu cmd từ đó. Trong trường hợp của tôi, tôi đã chạy cmd từ windows explorer và các biến môi trường không thay đổi trong khi khi bắt đầu cmd từ "run" (phím windows + r), các biến môi trường đã thay đổi .
Trong trường hợp của tôi, tôi chỉ phải giết tiến trình windows explorer từ trình quản lý tác vụ và sau đó khởi động lại từ trình quản lý tác vụ .
Khi tôi đã làm điều này, tôi có quyền truy cập vào biến môi trường mới từ một cmd được sinh ra từ windows explorer.
Tôi sử dụng đoạn mã sau trong tập lệnh bó của mình:
if not defined MY_ENV_VAR (
setx MY_ENV_VAR "VALUE" > nul
set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%
Bằng cách sử dụng SET sau SETX , có thể sử dụng biến "cục bộ" trực tiếp mà không cần khởi động lại cửa sổ lệnh. Và trong lần chạy tiếp theo, biến môi trường sẽ được sử dụng.
Tôi thích cách tiếp cận của sô cô la, như được đăng trong câu trả lời của kẻ hèn nhát ẩn danh, vì đó là một cách tiếp cận thuần túy. Tuy nhiên, nó để lại một tập tin tạm thời và một số biến tạm thời nằm xung quanh. Tôi đã tạo ra một phiên bản sạch hơn cho chính mình.
Tạo một tập tin refreshEnv.bat
ở đâu đó trên của bạn PATH
. Làm mới môi trường giao diện điều khiển của bạn bằng cách thực hiện 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.
Nếu nó chỉ liên quan đến một (hoặc một vài) lọ cụ thể mà bạn muốn thay đổi, tôi nghĩ cách dễ nhất là một cách giải quyết : chỉ cần đặt trong môi trường của bạn VÀ trong phiên bảng điều khiển hiện tại của bạn
Tôi có tập lệnh bó đơn giản này để thay đổi Maven của tôi từ Java7 thành Java8 (cả hai đều là vars) Thư mục bó nằm trong var PATH của tôi để tôi luôn có thể gọi ' j8 ' và trong bảng điều khiển của mình và trong môi trường được thay đổi:
j8.bat:
@echo off
set JAVA_HOME=%JAVA_HOME_8%
setx JAVA_HOME "%JAVA_HOME_8%"
Cho đến bây giờ tôi thấy điều này làm việc tốt nhất và dễ dàng nhất. Bạn có thể muốn điều này nằm trong một lệnh, nhưng đơn giản là nó không có trong Windows ...
Giải pháp tôi đã sử dụng vài năm nay:
@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
Chỉnh sửa: Woops, đây là phiên bản cập nhật.
Không có cách nào thẳng, như Kev nói. Trong hầu hết các trường hợp, việc sinh ra một hộp CMD khác sẽ đơn giản hơn. Khó chịu hơn, các chương trình đang chạy cũng không biết về các thay đổi (mặc dù IIRC có thể có một thông báo quảng bá để xem để được thông báo về sự thay đổi đó).
Điều tồi tệ hơn là: trong các phiên bản Windows cũ hơn, bạn phải đăng xuất sau đó đăng nhập lại để xem xét các thay đổi ...
Tôi sử dụng tập lệnh Powershell này để thêm vào biến PATH . Với một chút điều chỉnh nó cũng có thể hoạt động trong trường hợp của bạn.
#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%"
Cảm ơn bạn đã đăng câu hỏi này khá thú vị, ngay cả trong năm 2019 (Thật vậy, không dễ để làm mới cmd shell vì đây là một trường hợp duy nhất như đã đề cập ở trên), vì làm mới các biến môi trường trong windows cho phép thực hiện nhiều tác vụ tự động hóa mà không cần phải tự khởi động lại dòng lệnh.
Ví dụ: chúng tôi sử dụng điều này để cho phép phần mềm được triển khai và định cấu hình trên một số lượng lớn máy mà chúng tôi cài đặt lại thường xuyên. Và tôi phải thừa nhận rằng việc phải khởi động lại dòng lệnh trong quá trình triển khai phần mềm của chúng tôi sẽ rất không thực tế và sẽ yêu cầu chúng tôi tìm cách giải quyết không nhất thiết phải dễ chịu. Hãy đi đến vấn đề của chúng tôi. Chúng tôi tiến hành như sau.
1 - Chúng tôi có một tập lệnh bó mà lần lượt gọi một tập lệnh powershell như thế này
[tập tin: task.cmd] .
cmd > powershell.exe -executionpolicy unrestricted -File C:\path_here\refresh.ps1
2 - Sau này, tập lệnh refresh.ps1 làm mới các biến môi trường bằng các khóa đăng ký (GetValueNames (), v.v.). Sau đó, trong cùng một tập lệnh powershell, chúng ta chỉ cần gọi các biến môi trường mới có sẵn. Ví dụ, trong một trường hợp điển hình, nếu chúng ta vừa cài đặt nodeJS trước với cmd bằng các lệnh im lặng, sau khi hàm được gọi, chúng ta có thể gọi trực tiếp npm để cài đặt, trong cùng một phiên, các gói cụ thể như sau.
[tập tin: 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
Khi tập lệnh powershell kết thúc, tập lệnh cmd tiếp tục với các tác vụ khác. Bây giờ, một điều cần lưu ý là sau khi tác vụ hoàn thành, cmd vẫn không có quyền truy cập vào các biến môi trường mới, ngay cả khi tập lệnh powershell đã cập nhật chúng trong phiên của chính nó. Đó là lý do tại sao chúng ta thực hiện tất cả các tác vụ cần thiết trong tập lệnh powershell có thể gọi các lệnh tương tự như cmd.
Chỉnh sửa: điều này chỉ hoạt động nếu môi trường thay đổi bạn đang làm là kết quả của việc chạy một tệp bó.
Nếu một tệp bó bắt đầu bằng SETLOCAL
thì nó sẽ luôn làm sáng trở lại môi trường ban đầu của bạn khi thoát ngay cả khi bạn quên gọi ENDLOCAL
trước khi thoát hàng loạt hoặc nếu nó hủy bỏ bất ngờ.
Hầu như mọi tệp tin tôi viết đều bắt đầu SETLOCAL
vì trong hầu hết các trường hợp tôi không muốn các tác dụng phụ của thay đổi môi trường vẫn còn. Trong trường hợp tôi muốn thay đổi biến môi trường nhất định để truyền bên ngoài tệp bó thì lần cuối cùng của tôi ENDLOCAL
trông như thế này:
ENDLOCAL & (
SET RESULT1=%RESULT1%
SET RESULT2=%RESULT2%
)
Để giải quyết vấn đề này, tôi đã thay đổi biến môi trường bằng BOTH setx và set, sau đó khởi động lại tất cả các phiên bản của explorer.exe. Bằng cách này, bất kỳ quá trình nào sau đó được bắt đầu sẽ có biến môi trường mới.
Tập lệnh bó của tôi để làm điều này:
setx /M ENVVAR "NEWVALUE"
set ENVVAR="NEWVALUE"
taskkill /f /IM explorer.exe
start explorer.exe >nul
exit
Vấn đề với cách tiếp cận này là tất cả các cửa sổ explorer hiện đang mở sẽ bị đóng, đây có thể là một ý tưởng tồi - Nhưng hãy xem bài đăng của Kev để tìm hiểu lý do tại sao điều này là cần thiết