risposta-alla-domanda-sullo-sviluppo-web-bd.com

Esiste un comando per aggiornare le variabili di ambiente dal comando Prompt in Windows?

Se modifico o aggiungo una variabile di ambiente, devo riavviare il comando Prompt. Esiste un comando che potrei eseguire in questo modo senza riavviare CMD?

421
Eric Schoonover

È possibile acquisire le variabili di ambiente di sistema con uno script VBS, ma è necessario uno script bat per modificare effettivamente le variabili di ambiente correnti, quindi questa è una soluzione combinata.

Crea un file chiamato resetvars.vbs contenente questo codice e salvalo sul percorso:

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

crea un altro nome file resetvars.bat contenente questo codice, stessa posizione:

@echo off
%~dp0resetvars.vbs
call "%TEMP%\resetvars.bat"

Quando si desidera aggiornare le variabili di ambiente, eseguire solo resetvars.bat


Apologetica :

I due problemi principali che avevo in mente con questa soluzione erano

a. Non sono riuscito a trovare un modo semplice per esportare variabili di ambiente da uno script vbs al prompt Prompt, e

b. la variabile di ambiente PATH è una concatenazione dell'utente e delle variabili PATH di sistema.

Non sono sicuro di quale sia la regola generale per le variabili in conflitto tra utente e sistema, quindi ho scelto di rendere il sistema di override dell'utente, tranne che nella variabile PATH gestita in modo specifico.

Uso lo strano meccanismo vbs + bat + bat temporaneo per aggirare il problema dell'esportazione di variabili da vbs.

Nota : questo script non cancella le variabili.

Questo può probabilmente essere migliorato.

ADDED

Se devi esportare l'ambiente da una finestra di cmd a un'altra, usa questo script (chiamiamolo 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

Esegui exportvars.vbs nella finestra che vuoi esportare da , quindi passa alla finestra che vuoi esportare a , e digita:

"%TEMP%\resetvars.bat"
127
itsadok

Ecco cosa usa 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 .
87

In base alla progettazione non esiste un meccanismo incorporato per Windows per propagare una variabile di ambiente add/change/remove a un cmd.exe già in esecuzione, da un altro cmd.exe o da "Risorse del computer -> Proprietà -> Impostazioni avanzate -> Variabili di ambiente".

Se si modifica o si aggiunge una nuova variabile di ambiente al di fuori dell'ambito di un comando aperto esistente, chiedere di riavviare il comando Prompt o aggiungere manualmente utilizzando SET nel comando esistente Prompt.

L'ultima risposta accettata mostra un aggiramento parziale aggiornando manualmente tutte le variabili di ambiente in uno script. Lo script gestisce il caso d'uso di modificare le variabili d'ambiente a livello globale in "Risorse del computer ... Variabili d'ambiente", ma se una variabile d'ambiente viene modificata in un cmd.exe lo script non lo propagherà a un altro cmd.exe in esecuzione.

55
Kev

Su Windows 7/8/10 puoi installare Chocolatey che ha uno script per questo integrato.

Dopo aver installato Chocolatey, digita "refreshenv" senza virgolette.

48
jolly

Funziona su Windows 7: SET PATH=%PATH%;C:\CmdShortcuts

testato digitando echo% PATH% e ha funzionato, bene. imposta anche se apri un nuovo cmd, non c'è più bisogno di quei fastidiosi riavvii :)

33

Ho trovato questa risposta prima di trovare una soluzione più semplice.

Riavvia semplicemente Explorer.exe in Task Manager.

Non ho eseguito il test, ma potrebbe anche essere necessario riaprire il comando Prompt.

Credito a Timo Huovinen qui: Nodo non riconosciuto anche se installato con successo (se questo ti ha aiutato, per favore vai a dare credito commento di questo uomo).

31
wharding28

Usa "setx" e riavvia il prompt cmd

C'è uno strumento da riga di comando chiamato " setx " per questo lavoro. È per leggere e scrivere variabili di env. Le variabili persistono dopo che la finestra di comando è stata chiusa.

"Crea o modifica le variabili di ambiente nell'ambiente utente o di sistema, senza richiedere programmazione o scripting. Il comando setx recupera anche i valori delle chiavi e delle scritture di registro loro a file di testo. "

Nota: le variabili create o modificate da questo strumento saranno disponibili nelle finestre di comando future ma non nella finestra di comando CMD.exe corrente. Quindi, devi riavviare.

Se manca setx:


O modifica il registro

MSDN dice:

Per aggiungere o modificare a livello di programmazione le variabili di ambiente del sistema, aggiungerle alla chiave di registro HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment , quindi trasmettere un WM_SETTINGCHANGE messaggio con lParam impostato sulla stringa " Ambiente ".

Ciò consente alle applicazioni, come la Shell, di raccogliere i tuoi aggiornamenti.

25
Jens A. Koch

Chiamare questa funzione ha funzionato per me:

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

Il metodo migliore che ho trovato era quello di fare solo una query del Registro. Ecco il mio esempio.

Nel mio esempio ho fatto un'installazione utilizzando un file batch che ha aggiunto nuove variabili di ambiente. Avevo bisogno di fare tutto ciò non appena l'installazione era stata completata, ma non era in grado di generare un nuovo processo con quelle nuove variabili. Ho provato a generare un'altra finestra di Explorer e richiamato a cmd.exe e questo ha funzionato, ma su Vista e Windows 7, Explorer funziona solo come una singola istanza e normalmente come la persona che ha effettuato l'accesso. Ciò fallirebbe con l'automazione poiché ho bisogno dei miei credenziali di amministratore fare cose indipendentemente dall'esecuzione dal sistema locale o come amministratore sulla scatola. La limitazione a questo è che non gestisce cose come path, questo ha funzionato solo su semplici variabili ambientali. Questo mi ha permesso di utilizzare un batch per passare a una directory (con spazi) e copiare i file .exes ed ecc. Questo è stato scritto oggi da maggio risorse su stackoverflow.com

Chiamate batch originali a nuovo batch:

testenvget.cmd SDROOT (o qualunque sia la variabile)

@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

Inoltre c'è un altro metodo che ho trovato con varie idee diverse. Vedi sotto. Questo fondamentalmente otterrà la variabile del percorso più recente dal registro, tuttavia, ciò causerà una serie di problemi a causa del fatto che la query del registro darà delle variabili in sé, il che significa che ovunque ci sia una variabile questo non funzionerà, quindi per combattere questo problema fondamentalmente raddoppiare il percorso. Molto cattivo. Il metodo più perferito sarebbe: Set Path =% Path%; C:\Program Files\Software .... \

Indipendentemente da qui è il nuovo file batch, si prega di usare cautela.

@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
11

È possibile farlo sovrascrivendo la tabella dell'ambiente all'interno di un processo specificato stesso.

Come prova del concetto ho scritto questa app di esempio, che ha appena modificato una singola variabile di ambiente (nota) in un processo 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;
}

Uscita di esempio:

>set ENVTEST=abc

>cppTest.exe 13796
Target PID: 13796
PEB: 000007FFFFFD3000
UserProcessParameters: 00000000004B2F30
environment: 000000000052E700
Offset: 1528

>set ENVTEST
ENVTEST=def

Gli appunti

Questo approccio sarebbe anche limitato alle restrizioni di sicurezza. Se il target viene eseguito a quote più elevate o ad un account superiore (come SYSTEM), non avremmo il permesso di modificare la sua memoria.

Se si desidera eseguire questa operazione in un'app a 32 bit, gli offset hard codificati sopra passeranno rispettivamente a 0x10 e 0x48. Questi offset possono essere trovati scaricando le strutture _PEB e _RTL_USER_PROCESS_PARAMETERS in un debugger (ad esempio in WinDbg dt _PEB e dt _RTL_USER_PROCESS_PARAMETERS)

Per cambiare la proof-of-concept in una cosa di cui l'OP ha bisogno, sarebbe sufficiente enumerare le variabili attuali del sistema e dell'ambiente dell'utente (come documentato dalla risposta di @ tsadok) e scrivere l'intera tabella dell'ambiente nella memoria del processo di destinazione.

Modifica: La dimensione del blocco di ambiente viene anche memorizzata nella struttura _RTL_USER_PROCESS_PARAMETERS, ma la memoria viene allocata sull'heap del processo. Quindi da un processo esterno non avremmo la possibilità di ridimensionarlo e ingrandirlo. Ho provato a usare VirtualAllocEx per allocare memoria aggiuntiva nel processo di destinazione per l'ambiente storage ed è stato in grado di impostare e leggere una tabella completamente nuova. Sfortunatamente qualsiasi tentativo di modificare l'ambiente da mezzi normali si bloccherà e brucerà man mano che l'indirizzo non punta più sull'heap (si bloccherà in RtlSizeHeap).

7
josh poley

La cosa confusa potrebbe essere che ci sono alcuni punti in cui iniziare il cmd. Nel mio caso ho eseguito cmd da windows Explorer e le variabili dell'ambiente non sono cambiate mentre all'avvio cmd dal "run" (tasto windows + r) le variabili dell'ambiente sono state modificate .

Nel mio caso dovevo solo uccidere il processo di Windows Explorer dal task manager e quindi riavviarlo di nuovo dal task manager .

Una volta fatto ciò, ho avuto accesso alla nuova variabile di ambiente da un cmd che è stato generato da Windows Explorer.

5

Le variabili di ambiente vengono mantenute in HKEY_LOCAL_MACHINE\SYSTEM\ControlSet\Control\Session Manager\Environment.

Molti degli utili oggetti vv, come Path, sono memorizzati come REG_SZ. Esistono diversi modi per accedere al registro, incluso REGEDIT:

REGEDIT /E &lt;filename&gt; "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment" </ code>

L'output inizia con numeri magici. Quindi per cercarlo con il comando find deve essere digitato e reindirizzato: type <filename> | findstr -c:\"Path\"

Pertanto, se si desidera aggiornare la variabile percorso nella sessione di comando corrente con le proprietà di sistema, il seguente script batch funziona correttamente:

RefreshPath.cmd:

 
 @echo off 
 
 REM Questa soluzione richiede l'elevazione per leggere dal registro. 
 
 se esiste% temp%\env.reg del% temp%\env.reg/q /f

 REGEDIT/E% temp%\env.reg "HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Controllo\Gestione sessione\Ambiente "
 
 Se non esiste% temp%\env.reg (
 Echo" Impossibile scrivere il registro nella posizione temporanea "
 Exit 1 
) 
 
 SETLOCAL EnableDelayedExpansion 
 
 Per/f "token = 1,2 * delim ==" %% i in ('tipo% temp%\env.reg ^ | findstr -c:\"Path \" = ') do (
 set upath = %% ~ j 
 echo! upath: \\ = \!>% temp%\newpath 
) 
 
 ENDLOCAL 
 
 per/f "token = *" %% i in (% temp%\newpath) imposta percorso = %% i
5
Algonaut

Il riavvio di Explorer ha fatto questo per me, ma solo per i nuovi terminali cmd.

Il terminale che ho impostato sul percorso potrebbe già vedere la nuova variabile Path (in Windows 7).

taskkill /f /im Explorer.exe && Explorer.exe
4
Vince

Il modo più semplice per aggiungere una variabile al percorso senza riavviare la sessione corrente è aprire il comando Prompt e digitare:

PATH=(VARIABLE);%path%

e premere enter.

per verificare se la variabile è stata caricata, digitare

PATH

e premere enter. Tuttavia, la variabile sarà solo una parte del percorso fino al riavvio.

4
Richard Woodruff

Prova ad aprire un nuovo comando Richiedi come amministratore. Questo ha funzionato per me su Windows 10. (So che questa è una vecchia risposta, ma ho dovuto condividerla perché dover scrivere uno script VBS solo per questo è assurdo).

4
estebro

basta riavviare Explorer.exe >> testato su win 8 X64

3
SkyW3lker

Io uso il seguente codice nei miei script batch:

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

Usando SET dopo SETX è possibile usare la variabile "locale" direttamente senza riavviare la finestra di comando. E alla prossima esecuzione verrà utilizzata la variabile ambientale.

3
Sebastian

Mi è piaciuto l'approccio seguito da chocolatey, come pubblicato nella risposta anonima di codardo, dal momento che si tratta di un approccio di gruppo puro. Tuttavia, lascia un file temporaneo e alcune variabili temporanee in giro. Ho fatto una versione più pulita per me stesso.

Crea un file refreshEnv.bat da qualche parte sul PATH. Aggiorna l'ambiente della tua console eseguendo 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.
3
DieterDP

Prima installazione choco:

  • se si utilizza 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"

  • se si utilizza powershell Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

Quindi puoi eseguire refreshenv. Funziona sia su cmd che su PowerShell.

2

Se si tratta solo di uno (o pochi) vars specifici che vuoi cambiare, penso che il modo più semplice sia un workaround : appena inserito nel tuo ambiente E nella tua sessione di console corrente

  • Set metterà il var nella tua sessione corrente
  • SetX metterà la var nell'ambiente, ma NON nella tua sessione corrente

Ho questo semplice script batch per cambiare il mio Maven da Java7 a Java8 (che sono entrambi env vars) La cartella batch è nel mio PERCORSO var così posso sempre chiamare ' j8 ' e all'interno della mia console e nell'ambiente la mia variabile Java_HOME viene modificata:

j8.bat:

@echo off
set Java_HOME=%Java_HOME_8%
setx Java_HOME "%Java_HOME_8%"

Fino ad ora ho trovato questo funziona meglio e più facile. Probabilmente vuoi che questo sia in un comando, ma semplicemente non è lì in Windows ...

2

Grazie per aver postato questa domanda che è abbastanza interessante, anche nel 2019 (Infatti, non è facile rinnovare il cmd di Shell poiché è una singola istanza come menzionato sopra), perché il rinnovo delle variabili di ambiente in Windows consente di eseguire molte attività di automazione senza dover riavviare manualmente la riga di comando.

Ad esempio, lo usiamo per consentire la distribuzione e la configurazione del software su un numero elevato di macchine che reinstalliamo regolarmente. E devo ammettere che dover riavviare la linea di comando durante l'implementazione del nostro software sarebbe molto poco pratico e richiederebbe di trovare soluzioni alternative che non siano necessariamente piacevoli. Andiamo al nostro problema. Procediamo come segue.

1 - Abbiamo uno script batch che a sua volta chiama uno script PowerShell come questo

[file: task.cmd] .

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

2 - Dopo questo, lo script refresh.ps1 rinnova le variabili di ambiente utilizzando le chiavi del Registro di sistema (GetValueNames () e così via). Quindi, nello stesso script di PowerShell, dobbiamo solo chiamare le nuove variabili di ambiente disponibili. Ad esempio, in un caso tipico, se abbiamo appena installato nodeJS prima con cmd utilizzando i comandi silent, dopo che la funzione è stata chiamata, possiamo chiamare direttamente npm per installare, nella stessa sessione, pacchetti particolari come segue.

[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

Una volta finito lo script di PowerShell, lo script cmd prosegue con altre attività. Ora, una cosa da tenere a mente è che una volta completata l'attività, cmd non ha ancora accesso alle nuove variabili di ambiente, anche se lo script di PowerShell ha aggiornato quelle della propria sessione. Ecco perché facciamo tutti i compiti necessari nello script PowerShell che può chiamare gli stessi comandi di cmd, naturalmente.

1
Andy McRae

Non esiste una via diritta, come ha detto Kev. Nella maggior parte dei casi, è più semplice generare un'altra casella CMD. Ancora più fastidioso, i programmi in esecuzione non sono a conoscenza delle modifiche (anche se IIRC potrebbe essere un messaggio broadcast da guardare per essere avvisati di tale cambiamento).

È stato peggio: nelle versioni precedenti di Windows, dovevi disconnetterti e riaccedere per prendere in considerazione le modifiche ...

1
PhiLho

Uso questo script PowerShell per aggiungere alla variabile PERCORSO. Credo che con un piccolo aggiustamento possa funzionare anche nel tuo caso.

#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%"
1
Iulian Dita

no, io non la penso così ... puoi impostarli manualmente però. Quindi puoi metterli in un file batch o qualcosa del genere.

probabilmente potrebbe fare un programma di utilità/script (se qualcuno non lo ha già fatto) che interroga il registro e imposta l'ambiente corrente in modo che sia lo stesso

0
Keith Nicholas

Modifica: funziona solo se le modifiche dell'ambiente che stai facendo sono il risultato dell'esecuzione di un file batch.

Se un file batch inizia con SETLOCAL, si rimetterà sempre all'ambiente originale all'uscita anche se si dimentica di chiamare ENDLOCAL prima che il batch esca o si interrompa in modo imprevisto.

Quasi tutti i file batch che scrivo iniziano con SETLOCAL poiché nella maggior parte dei casi non voglio che rimangano gli effetti collaterali delle modifiche all'ambiente. Nei casi in cui desidero che determinate variabili di ambiente vengano propagate all'esterno del file batch, il mio ultimo ENDLOCAL ha il seguente aspetto:

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