Bir ortam değişkenini değiştirir veya eklersem, komut istemini yeniden başlatmam gerekir. CMD'yi yeniden başlatmadan bunu yapabileceğim bir komut var mı?
Bir ortam değişkenini değiştirir veya eklersem, komut istemini yeniden başlatmam gerekir. CMD'yi yeniden başlatmadan bunu yapabileceğim bir komut var mı?
Yanıtlar:
Sistem ortamı değişkenlerini bir vbs komut dosyasıyla yakalayabilirsiniz, ancak geçerli ortam değişkenlerini gerçekten değiştirmek için bir yarasa komut dosyasına ihtiyacınız vardır, bu nedenle bu birleşik bir çözümdür.
resetvars.vbs
Bu kodu içeren bir dosya oluşturun ve yola kaydedin:
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
bu kodu içeren başka bir dosya adı sıfırla .bat, aynı konumda:
@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"
Ortam değişkenlerini yenilemek istediğinizde, resetvars.bat
Özür dileme :
Bu çözümü ortaya koyduğum iki temel sorun
a. Ortam değişkenlerini bir vbs komut dosyasından komut istemine geri vermenin basit bir yolunu bulamadım ve
b. PATH ortam değişkeni, kullanıcının ve sistem PATH değişkenlerinin bir birleşimidir.
Kullanıcı ve sistem arasındaki değişkenler için genel kural ne olduğundan emin değilim, bu yüzden özellikle işlenen PATH değişkeni dışında, kullanıcı geçersiz kılma sistemi yapmak için seçildi.
Değişkenleri vbs'den dışa aktarma sorununu çözmek için garip vbs + bat + geçici bat mekanizmasını kullanıyorum.
Not : bu komut dosyası değişkenleri silmez.
Bu muhtemelen geliştirilebilir.
KATMA
Ortamı bir cmd penceresinden diğerine dışa aktarmanız gerekiyorsa, bu komut dosyasını kullanın (diyelim ki 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
Run exportvars.vbs
Eğer ihracat istediğiniz pencerede gelen , o zaman ihracat istediğiniz pencereye geçiş için ve tipi:
"%TEMP%\resetvars.bat"
İşte Chocolatey ne kullanıyor.
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
güncel oturumunuza güncellenmiş ortam değişkenlerini almak için çalışabilirsiniz .
Powershell
yaramalı mı? Sadece cmd.exe
benim için çalışıyor gibi görünüyor .
Windows 7/8/10'da, bu yerleşik için bir komut dosyası olan Chocolatey'yi yükleyebilirsiniz.
Chocolatey'i kurduktan sonra yazın refreshenv
.
Tasarım gereği bir değil orada yerleşik Windows için mekanizmanın başka cmd.exe veya My Computer" dan, ya zaten çalışan cmd.exeye bir ortam değişkeni ekleme / değiştirme / kaldırmayı yaymak için -> Özellikler -> Gelişmiş Ayarlar -> Ortam Değişkenleri".
Varolan bir açık komut isteminin kapsamı dışında yeni bir ortam değişkeni değiştirir veya eklerseniz, komut istemini yeniden başlatmanız veya varolan komut isteminde SET'i kullanarak el ile eklemeniz gerekir.
Kabul edilen en son yanıt , bir komut dosyasındaki tüm ortam değişkenlerini el ile yenileyerek kısmi bir çözüm olduğunu gösterir . Komut dosyası, "Bilgisayarım ... Ortam Değişkenleri" nde ortam değişkenlerini genel olarak değiştirmenin kullanım örneğini işler, ancak bir cmd.exe dosyasında bir ortam değişkeni değiştirilirse, komut dosyası bunu çalışan başka bir cmd.exe dosyasına yaymaz.
Sonunda daha kolay bir çözüm bulmadan önce bu cevaba rastladım.
explorer.exe
Görev Yöneticisi'nde yeniden başlatmanız yeterlidir .
Test etmedim, ama aynı zamanda komut istemini tekrar açmanız gerekebilir.
Timo Huovinen'e kredi : Başarılı bir şekilde kurulmuş olmasına rağmen düğüm tanınmıyor (bu size yardımcı olduysa, lütfen bu adamın yorum kredisini verin).
cmd
Yönetici olarak bir pencere başlatın . Komutu kullanın taskkill /f /im explorer.exe && explorer.exe
. Bu, explorer.exe işlemini öldürecek ve yeniden başlatacaktır.
Windows 7'de çalışır: SET PATH=%PATH%;C:\CmdShortcuts
echo% PATH% yazarak test edildi ve işe yaradı, iyi. ayrıca yeni bir cmd açarsanız, artık bu sinir bozucu yeniden başlatmaya gerek yok :)
setx
çünkü değiştirilmiş değişkenlere sahip olabilen mevcut ortamı devralır ve kalıcı olarak istediğim şeyi değil. Bu şekilde yapmak, değişkenleri kullanmak için konsolu yeniden başlatmaktan kaçınmamı sağlarken, gelecekte küresel olarak kullanılabilir olmama sorununu da önler.
"Setx" kullanın ve cmd istemini yeniden başlatın
Bu iş için " setx " adlı bir komut satırı aracı var . Bu için olduğunu okuma ve yazma env değişkenleri. Değişkenler komut penceresi kapatıldıktan sonra da devam eder.
"Programlama veya komut dosyası oluşturma gerektirmeden, kullanıcı veya sistem ortamında ortam değişkenleri oluşturur veya değiştirir. Setx komutu ayrıca kayıt defteri anahtarlarının değerlerini alır ve bunları metin dosyalarına yazar."
Not: Bu araç tarafından oluşturulan veya değiştirilen değişkenler gelecekteki komut pencerelerinde kullanılabilir, ancak geçerli CMD.exe komut penceresinde bulunmaz. Yani, yeniden başlatmalısınız.
Eğer setx
eksik:
Veya kayıt defterini değiştirin
MSDN diyor ki:
Sistem ortam değişkenlerini programlı olarak eklemek veya değiştirmek için, bunları HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environment kayıt defteri anahtarına ekleyin , ardından lParam " Environment " dizesine ayarlanmış bir WM_SETTINGCHANGE iletisi yayınlayın .
Bu, kabuk gibi uygulamaların güncellemelerinizi almasını sağlar.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE
mevcut kullanıcı ortamı: HKEY_CURRENT_USER\Environment\VARIABLE
%PATH%
sonra setx
1024 bayt bu kesecek! Ve aynen böyle, akşamı kayboldu
Bu işlevi çağırmak benim için çalıştı:
VOID Win32ForceSettingsChange()
{
DWORD dwReturnValue;
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
Ben geldi en iyi yöntem sadece bir Kayıt Defteri sorgusu yapmak oldu. İşte benim örneğim.
Örneğimde, yeni ortam değişkenleri ekleyen bir Batch dosyası kullanarak bir yükleme yaptım. Kurulum tamamlanır tamamlanmaz bununla bir şeyler yapmam gerekiyordu, ancak bu yeni değişkenlerle yeni bir süreç ortaya çıkaramadı. Ben başka bir explorer pencere yumurtlama test ve cmd.exe geri çağırdı ve bu çalıştı ama Vista ve Windows 7, Explorer sadece tek bir örnek olarak ve normalde giriş kişi olarak çalışır. Ben yönetici krediler için ihtiyacım çünkü bu otomasyon ile başarısız olacaktır yerel sistemden veya kutuda yönetici olarak çalıştırılmaksızın işleri yapın. Bunun sınırlaması, yol gibi şeyleri işlememesidir, bu sadece basit çevre değişkenleri üzerinde çalıştı. Bu, bir dizine (boşluklarla) geçmek ve .exes vb. Çalıştıran dosyalara kopyalamak için bir toplu iş kullanmamı sağladı.
Yeni Toplu İş için Orjinal Toplu İş çağrıları:
testenvget.cmd SDROOT (veya değişken ne olursa olsun)
@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
Ayrıca farklı fikirlerden ortaya çıkardığım başka bir yöntem daha var. Lütfen aşağıya bakın. Bu temelde en yeni yol değişkenini kayıt defterinden alacaktır, ancak bu, kayıt defteri sorgusunun kendi içinde değişkenler vereceği için bir dizi soruna neden olacaktır, bu, her yerde bu çalışmayacak bir değişken olduğu anlamına gelir. temel olarak yolu ikiye katlayın. Çok kötü. Daha perfered yöntem yapmak olurdu: Set Path =% Path%; C: \ Program Files \ Software .... \
Yeni toplu iş dosyası ne olursa olsun, lütfen dikkatli olun.
@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
Geçerli oturum için yeniden başlatmadan yola bir değişken eklemenin en kolay yolu komut istemini açmak ve yazmaktır:
PATH=(VARIABLE);%path%
düğmesine basın enter.
değişkeninizin yüklenip yüklenmediğini kontrol etmek için şunu yazın
PATH
düğmesine basın enter. Ancak, değişken siz yeniden başlatana kadar yolun yalnızca bir parçası olacaktır.
Bunu, belirtilen bir işlemin içindeki Ortam Tablosunun üzerine yazarak yapmak mümkündür.
Kavramın bir kanıtı olarak, sadece bir cmd.exe işleminde tek bir (bilinen) ortam değişkenini düzenleyen bu örnek uygulamayı yazdım:
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;
}
Örnek çıktı:
>set ENVTEST=abc
>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528
>set ENVTEST
ENVTEST=def
Bu yaklaşım aynı zamanda güvenlik kısıtlamalarıyla da sınırlı olacaktır. Hedef daha yüksek bir konumda veya daha yüksek bir hesapta (SYSTEM gibi) çalıştırılırsa, belleğini düzenleme iznimiz olmazdı.
Bunu 32 bit bir uygulamaya yapmak istiyorsanız, yukarıdaki sabit kodlu ofsetler sırasıyla 0x10 ve 0x48 olarak değişecektir. Bu aralıklar (WinDbg örneğin bir hata ayıklayıcı _PEB ve _RTL_USER_PROCESS_PARAMETERS yapılar damping bulunabilir dt _PEB
ve dt _RTL_USER_PROCESS_PARAMETERS
)
Kavram kanıtını OP'nin ihtiyaç duyduğu bir şeye dönüştürmek için, mevcut sistem ve kullanıcı ortamı değişkenlerini (@ tsadok'un cevabı ile belgelendiği gibi) numaralandırır ve tüm ortam tablosunu hedef sürecin hafızasına yazar.
Düzenleme: Ortam bloğunun boyutu da _RTL_USER_PROCESS_PARAMETERS yapısında saklanır, ancak bellek işlemin yığınına ayrılır. Yani harici bir süreçten, onu yeniden boyutlandırma ve büyütme yeteneğimiz olmazdı. Ortam depolama için hedef işlemde ek bellek ayırmak için VirtualAllocEx kullanarak oynadım ve tamamen yeni bir tablo ayarlamak ve okumak mümkün. Ne yazık ki, adres artık yığına işaret etmediği için ortamı normal yollardan değiştirme denemesi çökecek ve yanacaktır (RtlSizeHeap'te çökecektir).
Ortam değişkenleri HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Session Manager \ Environment içinde tutulur.
Path gibi yararlı env değişkenlerinin çoğu REG_SZ olarak depolanır. REGEDIT dahil kayıt defterine erişmenin birkaç yolu vardır:
REGEDIT /E <filename> "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment"
Çıktı sihirli sayılarla başlar. Bu nedenle find komutuyla aramak için yazılması ve yeniden yönlendirilmesi gerekir:type <filename> | findstr -c:\"Path\"
Bu nedenle, geçerli komut oturumunuzdaki yol değişkenini sistem özelliklerinde bulunanlarla yenilemek istiyorsanız, aşağıdaki toplu komut dosyası iyi çalışır:
RefreshPath.cmd:
@Eko kapalı REM Bu çözüm, kayıt defterinden okumak için yükseltme ister. Varsa% temp% \ env.reg del% temp% \ env.reg / q / f REGEDIT / E% temp% \ env.reg "HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet001 \ Control \ Session Manager \ Environment" yoksa% temp% \ env.reg ( echo "Geçici konuma kayıt defteri yazılamıyor" çıkış 1 ) SETLOCAL EnableDelayedExpansion / f "belirteçleri = 1,2 * delims ==" %% i in ('tür% temp% \ env.reg ^ | findstr -c: \ "Yol \" =') yap ( setath = %% ~ j echo! upath: \\ = \! >% Temp% \ NEWPATH ) ENDLOCAL / f "belirteçleri = *" için %% i (% temp% \ newpath) yolunu ayarla = %% i
Kafa karıştırıcı olan şey, cmd'yi başlatmak için birkaç yer olması olabilir. Benim durumumda ben koştu kaşif pencerelerden cmd ve çevre değişmedi değişkenler başlatırken ederken "run" dan cmd ortamı (pencereler tuşu + r) değişkenler değiştirildi .
Benim durumumda , görev çubuğundan windows explorer işlemini öldürmek ve sonra görev yöneticisinden yeniden başlatmak zorunda kaldım .
Bunu yaptıktan sonra yeni bir ortam değişkenine Windows Gezgini'nden çıkan bir cmd'den erişebildim.
Toplu komut dosyalarında aşağıdaki kodu kullanıyorum:
if not defined MY_ENV_VAR (
setx MY_ENV_VAR "VALUE" > nul
set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%
Kullanarak SET sonra setx o komut penceresi yeniden başlatmadan doğrudan "yerel" değişkeni kullanmak mümkündür. Ve bir sonraki çalışmada, çevre değişkeni kullanılacaktır.
Anonim bir korkak cevabında yayınlandığı gibi chocolatey tarafından takip edilen yaklaşımı beğendim, çünkü saf bir toplu yaklaşım. Bununla birlikte, geçici bir dosya ve bazı geçici değişkenler etrafta kalır. Kendim için daha temiz bir versiyon yaptım.
refreshEnv.bat
Üzerinde bir yerde bir dosya oluşturun PATH
. Konsol ortamınızı çalıştırarak yenileyin 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.
Değiştirmek istediğiniz sadece bir (veya birkaç) spesifik varyasyonu ilgilendiriyorsa, en kolay yolun bir çözüm olduğunu düşünüyorum : sadece ortamınızda VE mevcut konsol oturumunuzda
Benim Maven Java7 Java8 (her ikisi de env vars olan) değiştirmek için bu basit toplu komut dosyası var Her zaman ' j8 ' çağırabilir ve benim konsol ve çevre içinde benim JAVA_HOME var böylece toplu klasör PATH var değişti:
j8.bat:
@echo off
set JAVA_HOME=%JAVA_HOME_8%
setx JAVA_HOME "%JAVA_HOME_8%"
Şimdiye kadar bu işi en iyi ve en kolay buluyorum. Muhtemelen bunun tek bir komutta olmasını istiyorsunuz, ancak sadece Windows'ta yok ...
Birkaç yıldır kullandığım çözüm:
@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
Düzenleme: Woops, işte güncellenmiş sürüm.
Kev'nın dediği gibi düz bir yol yok. Çoğu durumda, başka bir CMD kutusu oluşturmak daha kolaydır. Daha rahatsız edici bir şekilde, çalışan programlar da değişikliklerin farkında değildir (IIRC, bu değişiklikten haberdar olmak için izlemek için bir yayın mesajı olabilir).
Daha da kötüsü: Windows'un eski sürümlerinde, değişiklikleri hesaba katmak için oturumu kapatıp yeniden oturum açmanız gerekiyordu ...
PATH değişkenine eklemek için bu Powershell betiğini kullanıyorum . Küçük bir ayarlama ile sizin durumunuzda da çalışabileceğine inanıyorum.
#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'da bile oldukça ilginç olan bu soruyu yayınladığınız için teşekkür ederiz (Gerçekten de, yukarıda belirtildiği gibi tek bir örnek olduğu için kabuk cmd'sini yenilemek kolay değildir), çünkü pencerelerde ortam değişkenlerini yenilemek, birçok otomasyon görevini komut satırını el ile yeniden başlatmanız gerekir.
Örneğin, yazılımı düzenli olarak yeniden yüklediğimiz çok sayıda makineye dağıtıp yapılandırmak için kullanıyoruz. Ve yazılımımızın konuşlandırılması sırasında komut satırını yeniden başlatmanın çok pratik olmayacağını ve mutlaka hoş olmayan geçici çözümler bulmamızı gerektirdiğini itiraf etmeliyim. Sorunumuza geçelim. Aşağıdaki gibi devam ediyoruz.
1 - Buna benzer bir powershell betiği çağıran bir toplu komut dosyamız var
[dosya: görev.cmd] .
cmd > powershell.exe -executionpolicy unrestricted -File C:\path_here\refresh.ps1
2 - Bundan sonra refresh.ps1 betiği, kayıt defteri anahtarlarını (GetValueNames () vb.) Kullanarak ortam değişkenlerini yeniler. Daha sonra, aynı powershell betiğinde, kullanılabilir olan yeni ortam değişkenlerini çağırmamız gerekir. Örneğin, tipik bir durumda, nodeJS'yi daha önce cmd ile sessiz komutları kullanarak kurduysak, işlev çağrıldıktan sonra, aynı oturumda aşağıdaki gibi belirli paketleri kurmak için doğrudan npm'yi çağırabiliriz.
[dosya: 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 betiği bittiğinde, cmd betiği diğer görevlerle devam eder. Şimdi, akılda tutulması gereken bir şey, görev tamamlandıktan sonra, cmd'nin yeni ortam değişkenlerine hala erişimi yoktur, powershell betiği kendi oturumunda bunları güncellemiş olsa bile. Bu yüzden elbette cmd ile aynı komutları çağırabilecek powershell betiğinde gerekli tüm görevleri yapıyoruz.
Düzenle: Bu yalnızca, yaptığınız ortam değişiklikleri bir toplu iş dosyası çalıştırmanın bir sonucuysa çalışır.
Bir toplu iş dosyası ile SETLOCAL
başlarsa ENDLOCAL
, toplu iş çıkmadan önce aramayı unutsanız veya beklenmedik bir şekilde sonlandırsa bile, çıkışta her zaman orijinal ortamınıza geri döner .
Yazdığım hemen hemen her toplu iş dosyası başlar, SETLOCAL
çünkü çoğu durumda ortam değişikliklerinin yan etkilerinin kalmasını istemiyorum. Belirli ortam değişkeni değişikliklerinin toplu iş dosyasının dışında yayılmasını istediğiniz durumlarda, sonuncum ENDLOCAL
şöyle görünür:
ENDLOCAL & (
SET RESULT1=%RESULT1%
SET RESULT2=%RESULT2%
)
Bunu çözmek için, BOTH setx ve set kullanarak ortam değişkenini değiştirdim ve sonra explorer.exe'nin tüm örneklerini yeniden başlattım. Bu şekilde daha sonra başlatılan herhangi bir işlem yeni ortam değişkenine sahip olacaktır.
Bunu yapmak için toplu iş komut dosyası:
setx /M ENVVAR "NEWVALUE"
set ENVVAR="NEWVALUE"
taskkill /f /IM explorer.exe
start explorer.exe >nul
exit
Bu yaklaşımla ilgili sorun şu anda açık olan tüm explorer pencerelerinin kapatılmasıdır, bu muhtemelen kötü bir fikirdir - Ama bunun neden gerekli olduğunu öğrenmek için Kev tarafından gönderilen gönderiye bakın.