Windowsのコマンドプロンプトから環境変数を更新するコマンドはありますか?


480

環境変数を変更または追加した場合、コマンドプロンプトを再起動する必要があります。CMDを再起動せずにこれを実行できるコマンドはありますか?


38
実際には、それらを表示する必要があるすべてのプログラムを再起動する必要があります。環境は起動時にプロセスのメモリにコピーされるため、システム定義のenvvarsとはまったく関係がありません。
ジョーイ

15
これらを読んだ後、私はスプーンがないことに気付きました;)現実の世界では、cmdを再起動するだけです。
n611x007 2013

ないコマンドが、そうではない、かなりの答えは、私が読んでいる場合のWin32 APIを使用して、それのためのサポートがあり、正しく、以下:support.microsoft.com/en-us/help/104011/... Shoudはにその行をコンパイルすることができます単純なCプログラムで、環境変数の更新に続いて実行します。
Charles Grunwald

WM_SETTINGCHANGE(@CharlesGrunwaldによって言及されたwin32 api)は、次のスレッドに従ってcmd.exeウィンドウに対して機能しません:github.com/chocolatey/choco/issues/1589-それが、refreshenvコマンドを作成した理由です
davr

回答:


137

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


Apologetics

この解決策を思いついた2つの主な問題は

a。環境変数をvbsスクリプトからコマンドプロンプトにエクスポートする簡単な方法が見つかりませんでした。

b。PATH環境変数は、ユーザーとシステムのPATH変数を連結したものです。

ユーザーとシステムの間で変数を競合させるための一般的なルールが何かわからないので、特別に処理されるPATH変数を除いて、ユーザーオーバーライドシステムを作成することにしました。

奇妙なvbs + bat + temporary 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"

2
おそらく、FOR / F "tokens = 1、*" %% c IN( 'resetvars.vbs')DO構文を使用して一時ファイルを回避できます
tzot

2
私の答えで言ったように、「または、既存のコマンドプロンプトでSETを使用して手動で追加します。」これが効果的なことです。でも良い答えです。
ケブ

2
@itsadok-これが受け入れられた回答であることを考えると、スクリプトを前後関係に置くために、最初に簡単な説明を追加する必要があります。つまり、上記のように手動で更新したり、cmd.exeを再起動したりせずに、env varの変更を開いているcmd.exeに伝達することはできないことを指摘します。
ケブ

スクリプトは、「マイコンピュータ...環境変数」で環境変数をグローバルに変更するユースケースを処理しますが、環境変数が1つのcmd.exeで変更された場合、スクリプトはそれを別の実行中のcmd.exeに伝播しません。おそらく一般的なシナリオです。
ケブ

1
@Keyslinger:それは実際には不可能です。生成されたプログラムは、それ自体の環境を更新できますが、実行中のcmd.exeインスタンスの環境は更新できません。バッチファイルは、cmd.exeの同じインスタンス内で実行されるため、cmd.exe環境を更新できます。
Ben Voigt 2014年

112

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 .

65
+1 Chocolateyがインストールされている場合は、実行RefreshEnvして、更新された環境変数を現在のセッションに取り込むことができます。
Martin Valgur 2016

2
これは非常に便利なユーティリティソフトウェアです。共有してくれてありがとう。
Sabuncu 2017年

10
注:Chocolateyはレポを移動していると、このスクリプトの最新バージョンは(いくつかのバグ修正と)ここで見つけることができます:github.com/chocolatey/choco/blob/master/src/...
マイケル・バリ

1
これも機能しPowershellますか?それcmd.exeは私にとってはうまくいくようです。
craq

1
PowerShell、@ craqで動作します。Windows10 x64を実行しています。
mazunki

100

Windows 7/8/10では、この組み込みのスクリプトを含むChocolateyをインストールできます。

Chocolateyをインストールしたら、と入力しrefreshenvます。


これは有効な回答である、それをdownvotedのだ男から聞いていいだろう
the_joric

2
何が悪いのですか?$> refreshenv 'refreshenv'は、内部または外部のコマンド、操作可能なプログラム、またはバッチファイルとして認識されません。
aclokay 2017

@aclokayわかりません。デバッグするur system confの詳細を入力してください。その間、ここで同様の未解決の問題を参照できます。github.com/chocolatey/choco/issues/250
ジョリー

それも私にはうまくいきません。私はW7プロフェッショナルです。たぶん、それはより完全なバージョンでのみ機能します。
その他、

1
(私にとってそうであったように)refreshenvがスクリプトの時期尚早に存在する場合は、代わりに「call RefreshEnv.cmd」を使用できます。(github.com/chocolatey/choco/issues/1461を参照)
sfiss

59

設計上、Windowsが別のcmd.exeから、または「マイコンピュータ->プロパティ->詳細設定->」から、すでに実行中のcmd.exeに環境変数の追加/変更/削除を伝達するための組み込みのメカニズムはありません。環境変数"。

既存のオープンコマンドプロンプトの範囲外で新しい環境変数を変更または追加する場合は、コマンドプロンプトを再起動するか、既存のコマンドプロンプトでSETを使用して手動で追加する必要があります。

最新の受け入れ答えを示して手動でリフレッシュすることにより、部分の周りの仕事のすべてのスクリプトで環境変数を。このスクリプトは、「マイコンピュータ...環境変数」で環境変数をグローバルに変更するユースケースを処理しますが、あるcmd.exeで環境変数が変更された場合、スクリプトは実行中の別のcmd.exeにそれを伝播しません。


誰かがこの問題の実用的な解決策を持っている場合、私は定期的にチェックインし、受け入れられた回答を変更する場合があります。
Eric Sc​​hoonover、

1
これは、尋ねられた質問に答えないからといって、受け入れられた答えであってはなりません。この質問は、答えが見つかるまで、回答が承認されないままにしておく必要があります。
2008年

4
不愉快なことに、cmd.exeの余分なインスタンスはカウントされません。変更が新しいcmd.exeに反映される前に、それらすべてを強制終了する必要があります。

6
否定的なコメントとこの回答のダウンマークは、スタックオーバーフローの破損が時々どのように発生するかを示しています。Kevが正しい答えを出しました。あなたが気に入らないからといってそれをマークダウンする理由はありません。
David Arno、

ケブは間違いなく質問に答えます。問題は、組み込みのソリューションがないことです。
Eric Sc​​hoonover、

40

最終的にはより簡単な解決策を見つける前に、私はこの答えに出くわしました。

explorer.exeタスクマネージャで再起動するだけです。

テストはしませんでしたが、コマンドプロンプトを再度開く必要がある場合もあります。

功績ティモHuovinenここでは:正常にインストールがノードが認識されない(これはあなたを助けている場合、この人のコメントを信用を与える行ってください)。


このブログに記載されているように、ソリューションのルートでコマンドプロンプトを開くことができるように、外部ツールをVisual Studioに追加しようとしていたため、ここに到着しました: neverindoubtnet.blogspot.com/2012/10/… ...同様の問題がありました...パス変数に「git」を表示させようとしていました。gitディレクトリをPATH変数に追加しましたが、Visual Studioから開くコマンドプロンプトに表示されません。簡単な解決策は、Visual Studioを再起動することでした。次に、PATH変数への新しい追加がcmdに表示されました。
David Barrows、2015

4
そのソリューションはWindows 10で私を助けます
ganchito55

7
問題は、「CMDを再起動せずにこれ実行できるコマンドを実行できるか」でした。
フロリアンF

タスクマネージャーから、explorer.exeを再起動できませんでした。終了するだけです。やりましたが、タスクバーが壊れています。explorer; exeを開始するのはとても簡単です。「Ctrl + Shift +エスケープ」->ファイル->「新しいタスクを実行」->「explorer.exe」が私のために仕事をしてみましょう。そして、はい、新しいcmdウィンドウですべてのenv varが使用された後。みんなありがとう
Oscar

良い解決策、ありがとう!@Oscarのコメントを展開して対処するには:cmd管理者としてウィンドウを起動します。コマンドを使用しtaskkill /f /im explorer.exe && explorer.exeます。これにより、explorer.exeプロセスが強制終了され、再起動されます。
S3DEV 2018年

32

これはWindows 7で機能します。 SET PATH=%PATH%;C:\CmdShortcuts

echo%PATH%と入力してテストしましたが、うまくいきました。また、新しいcmdを開いた場合も設定されます。これらの厄介な再起動は不要です:)


1
私(Win7 x64)の「新しいcmd」では機能しません。screenvideoを
Igor

26
これは、尋ねられている質問を解決するものでも、解決すべきでもありません。元の質問は、環境変数をその端末の外部で設定された値に更新する方法です。
csauve 2015年

これは質問の答えにはなりませんが、最良のソリューションの半分を提供します。私はこれを使用して-設定しているすべての変数に対して-次に、コントロールパネルを開いて環境変数をグローバルに追加します。私が使用したくないのsetxは、変更された変数があり、永続的に必要な変数がない可能性がある現在の環境を継承するためです。このようにすることで、変数を使用するためにコンソールを再起動する必要がなくなり、将来的に変数をグローバルに使用できなくなるという問題を回避できます。
dgo

25

「setx」を使用してコマンドプロンプトを再起動します

このジョブには、「setx」というコマンドラインツールがあります。これは env変数を読み書きするためのものです。変数は、コマンドウィンドウが閉じられた後も存続します。

これは、「プログラミングやスクリプトを必要とせずに、ユーザーまたはシステム環境で環境変数を作成または変更します。setxコマンドは、レジストリキーの値を取得し、それらをテキストファイルに書き込みます。」

注:このツールで作成または変更された変数は、将来のコマンドウィンドウで使用できますが、現在のCMD.exeコマンドウィンドウでは使用できません。したがって、再起動する必要があります。

ない場合setx


またはレジストリを変更します

MSDNは言う:

プログラムでシステム環境変数を追加または変更するには、それらをHKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environmentレジストリキーに追加してから、 lParamが文字列 " Environment "に設定されたWM_SETTINGCHANGE メッセージをブロードキャストします。

これにより、シェルなどのアプリケーションが更新を取得できます。


1
setxを使用して環境変数を読み取る方法を詳しく説明していただけますか?さまざまなドキュメントを調べてきましたが、表示されていません。:-/
マークリバウ

2
setx VARIABLE -k "HKEY_LOCAL_MACHINE \ Software \ Microsoft \ WindowsNT \ CurrentVersion \ CurrentVersion" echo%VARIABLE%
Jens A. Koch

3
現在のシステム環境:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE現在のユーザー環境: HKEY_CURRENT_USER\Environment\VARIABLE
Mark Ribau

5
setx /?「ローカルシステムでは、このツールによって作成または変更された変数は、将来のコマンドウィンドウで使用できますが、現在の CMD.exeコマンドウィンドウでは使用できません。」OPは現在のcmdを更新したかった。
Superole 2014年

4
バイヤーは注意してください!あなたが持っている場合は特に長く%PATH%、その後setx1024バイトにこれを切り捨てることがあります!そしてちょうどそのように、彼の夕方は消えました
FaCE 2016

15

この関数を呼び出すとうまくいきました:

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

8
すべてのプログラムがこのメッセージを聞くわけではありません(実際、ほとんどのプログラムは聞いていません)
Rehan Khwaja

いいえ、非GUIプログラムでも機能します。リスニングプログラムについては...再起動されたプログラムが更新された環境を確実に受信するかどうかの問題であり、これはそれを提供します。
user2023370 2015

11

私が思いついた最善の方法は、単にレジストリクエリを実行することでした。これが私の例です。

私の例では、新しい環境変数を追加したバッチファイルを使用してインストールを行いました。インストールが完了するとすぐにこれで何かをする必要がありましたが、これらの新しい変数を使用して新しいプロセスを生成できませんでした。別のエクスプローラーウィンドウの起動をテストしてcmd.exeにコールバックしましたが、これは機能しましたが、VistaおよびWindows 7では、エクスプローラーは単一のインスタンスとしてのみ実行され、通常はログインしたユーザーとして実行されます。ローカルシステムから実行するか、ボックスの管理者として実行するかに関係なく、処理を実行します。これに対する制限は、それがパスなどを処理しないことです。これは単純な環境変数でのみ機能しました。これにより、バッチを使用して(スペースのある)ディレクトリに移動し、ファイルをコピーして.exeなどを実行できるようになりました。これは、stackoverflow.comのリソースから本日作成されました

新しいバッチへの元のバッチ呼び出し:

testenvget.cmd SDROOT(または任意の変数)

@ECHO OFF
setlocal ENABLEEXTENSIONS
set keyname=HKLM\System\CurrentControlSet\Control\Session Manager\Environment
set value=%1
SET ERRKEY=0

REG QUERY "%KEYNAME%" /v "%VALUE%" 2>NUL| FIND /I "%VALUE%"
IF %ERRORLEVEL% EQU 0 (
ECHO The Registry Key Exists 
) ELSE (
SET ERRKEY=1
Echo The Registry Key Does not Exist
)

Echo %ERRKEY%
IF %ERRKEY% EQU 1 GOTO :ERROR

FOR /F "tokens=1-7" %%A IN ('REG QUERY "%KEYNAME%" /v "%VALUE%" 2^>NUL^| FIND /I "%VALUE%"') DO (
ECHO %%A
ECHO %%B
ECHO %%C
ECHO %%D
ECHO %%E
ECHO %%F
ECHO %%G
SET ValueName=%%A
SET ValueType=%%B
SET C1=%%C
SET C2=%%D
SET C3=%%E
SET C4=%%F
SET C5=%%G
)

SET VALUE1=%C1% %C2% %C3% %C4% %C5%
echo The Value of %VALUE% is %C1% %C2% %C3% %C4% %C5%
cd /d "%VALUE1%"
pause
REM **RUN Extra Commands here**
GOTO :EOF

:ERROR
Echo The the Enviroment Variable does not exist.
pause
GOTO :EOF

また、いろいろなアイデアから思いついた方法もあります。下記を参照してください。これは基本的に、レジストリから最新のパス変数を取得しますが、レジストリクエリ自体が変数を提供するため、これは多くの問題を引き起こします。基本的にパスを2倍にします。非常に厄介です。より好ましい方法は次のようにすることです: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

8

現在のセッションで再起動せずに変数をパスに追加する最も簡単な方法は、コマンドプロンプトを開いて次のように入力することです。

PATH=(VARIABLE);%path%

そして押す enterます。

変数が読み込まれたかどうかを確認するには、次のように入力します。

PATH

を押しenterます。ただし、再起動するまで、変数はパスの一部のみになります。


私にとっては
うまくいき

7

指定されたプロセス自体の中で環境テーブルを上書きすることにより、これを行うことができます。

概念実証として、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 _PEBdt _RTL_USER_PROCESS_PARAMETERS)で

概念実証をOPに必要なものに変更するには、現在のシステムとユーザー環境変数(@tsadokの回答で文書化されているような)を列挙し、環境テーブル全体をターゲットプロセスのメモリに書き込むだけです。

編集:環境ブロックのサイズも_RTL_USER_PROCESS_PARAMETERS構造体に格納されますが、メモリはプロセスのヒープに割り当てられます。したがって、外部プロセスからは、サイズを変更して大きくすることができません。VirtualAllocExを使用して、ターゲットプロセスに追加のメモリを環境ストレージに割り当てることを試し、まったく新しいテーブルを設定して読み取ることができました。残念ながら、通常の方法で環境を変更しようとすると、アドレスがヒープを指していないため、クラッシュして書き込みが発生します(RtlSizeHeapでクラッシュします)。


6

環境変数はHKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Session Manager \ Environmentに保持されます。

Pathなどの便利な環境変数の多くは、REG_SZとして格納されます。REGEDITを含むレジストリにアクセスするには、いくつかの方法があります。

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

出力はマジックナンバーで始まります。したがって、findコマンドで検索するには、入力してリダイレクトする必要があります。type <filename> | findstr -c:\"Path\"

したがって、現在のコマンドセッションのパス変数をシステムプロパティの内容で更新したい場合は、次のバッチスクリプトが適切に機能します。

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 \ Environment"

    存在しない場合%temp%\ env.reg(
       echo "一時的な場所にレジストリを書き込めません"
       1番出口
       )

    SETLOCAL EnableDelayedExpansion

    / f "tokens = 1,2 * delims ==" %% i in( 'type%temp%\ env.reg ^ | findstr -c:\ "Path \" =')do(
       セットアップ= %%〜j
       echo!upath:\\ = \!>%temp%\ newpath
       )

     ENDLOCAL

     / f "tokens = *"の%% i(%temp%\ newpath)はパスを設定= %% i

5
環境変数はレジストリに保持されません。レジストリに保持されているのはテンプレートであり、Windows Explorerなどのプログラムは、通知されたときに環境変数を(再)構築します。実際の環境変数はプロセスごとにあり、各プロセスのアドレス空間に格納されます。最初は親プロセスから継承され、その後プロセスの気まぐれで変更できます。
JdeBP 2011年

5

管理者として新しいコマンドプロンプトを開いてみてください。これは私にとってWindows 10で機能しました(これは古い答えであることはわかっていますが、これだけのためにVBSスクリプトを記述する必要があるのはばかげているので、共有する必要がありました)。


5

エクスプローラーを再起動すると、これは私のために行われましたが、新しいcmd端末に対してのみでした。

パスを設定した端末は、新しいパス変数を既に表示している可能性があります(Windows 7)。

taskkill /f /im explorer.exe && explorer.exe

5

混乱を招くのは、コマンドを開始する場所がいくつかあることです。私の場合、私は走ったWindowsエクスプローラからcmdをと環境変数が変更されていない起動時にしながら、「ファイル名を指定して実行」から、CMD(Windowsキー+ rを)環境変数が変更されました

私の場合、タスクマネージャーからWindowsエクスプローラープロセスを強制終了し、タスクマネージャーから再起動する必要がありました

これを実行すると、Windowsエクスプローラーから生成されたコマンドから新しい環境変数にアクセスできました。


3

バッチスクリプトで次のコードを使用します。

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

使用してSETをした後、SETXコマンドウィンドウを再起動せずに、直接「ローカル」変数を使用することが可能です。そして、次の実行では、環境変数が使用されます。


私はあなたがやったことを取得していますが、おそらく彼は並列スクリプト用の何かを望んでいます。それ以外の場合は、setxを使用しても意味がありません。setで十分です。
JasonXA

3

匿名の臆病者の回答に投稿されているように、チョコレートに続くアプローチが好きでした。これは、純粋なバッチアプローチであるためです。ただし、一時ファイルといくつかの一時変数が残ります。自分用にクリーナーバージョンを作りました。

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.

これは%CLIENTNAME%にも適用されますか?- -私のために動作しませんでしたstackoverflow.com/questions/37550160/...
イゴール・L.

%CLIENTNAME%は私の環境では使用できません。質問を読んで、外部のプロセスによって設定されたものであると想定します。(プロセスが子プロセスを開始すると、その子の環境を調整できます。)プロセスは実際の環境変数の一部ではないため、このスクリプトによって更新されることはありません。
DieterDP 2016年

こんにちは@DieterDP、あなたの解決策は私のために働きます!64ビットマシンでWindows 10を使用しています。「エラー:指定されたレジストリキーまたは値が見つかりませんでした。」というエラーが表示されます。それにもかかわらず、環境変数の更新は成功しています。エラーはどこから発生しますか?
K.Mulier

実際にテストせずに言うのは難しいですが、W10のレジストリ構造は多少異なると思います。必要に応じて、コマンドラインでコマンドを実行してエラーを探してみてください。
DieterDP 2016

2

変更したい特定の1つ(またはいくつか)のvarにのみ関係する場合、最も簡単な方法は回避策であると思います。環境に設定し、現在のコンソールセッションに設定するだけです。

  • セットは現在のセッションに変数を配置します
  • SetXはvarを環境に入れますが、現在のセッションには入れません

私のMavenをJava7からJava8に変更するためのこの単純なバッチスクリプトがあります(どちらも環境変数です)バッチフォルダーはPATH変数にあるため、常に ' j8 'を呼び出すことができ、コンソール内と環境内でJAVA_HOME 変数変更されます:

j8.bat:

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

今までのところ、これが最も効果的で簡単に機能します。たぶんこれを1つのコマンドに含めたいのですが、Windowsにはありません...


2

私が数年間使用してきたソリューション:

@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

編集:おっと、ここに更新されたバージョンがあります。


私はあなたの答えが好きです。ここに私の質問に同じ答えを投稿stackoverflow.com/q/61473551/1082063、私はとしてそれを受け入れるの答え。ありがとう。
David I. McIntosh

1

ケブが言ったように、まっすぐな道はありません。ほとんどの場合、別のCMDボックスを生成する方が簡単です。さらに厄介なことに、実行中のプログラムも変更を認識しません(IIRCは、そのような変更について通知されるために注意するブロードキャストメッセージがあるかもしれませんが)。

さらに悪いことに、古いバージョンのWindowsでは、変更を考慮に入れるためにログオフしてからログアウトする必要がありました...


1

この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%"

1

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スクリプトは他のタスクを続行します。今、覚えておくべきことの1つは、タスクが完了した後、Powershellスクリプトが独自のセッションでそれらを更新した場合でも、cmdはまだ新しい環境変数にアクセスできないことです。そのため、もちろんcmdと同じコマンドを呼び出すことができるPowerShellスクリプトで必要なすべてのタスクを実行します。


0

編集:これは、実行している環境の変更がバッチファイルの実行の結果である場合にのみ機能します。

バッチファイルがで始まる場合は、バッチが終了する前SETLOCALに呼び出しを忘れたENDLOCAL場合や、バッチが予期せずに中止された場合でも、終了時に常に元の環境に戻ります。

ほとんどのSETLOCAL場合、環境の変更による影響を残したくないので、ほとんどすべてのバッチファイルは最初から作成します。特定の環境変数の変更をバッチファイルの外に反映させたい場合、最後のファイルはENDLOCAL次のようになります。

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

-1

これを解決するために、setxとsetの両方を使用して環境変数を変更し、explorer.exeのすべてのインスタンスを再起動しました。このようにして、その後に開始されたプロセスはすべて新しい環境変数を持ちます。

これを行うための私のバッチスクリプト:

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

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

このアプローチの問題は、現在開かれているすべてのエクスプローラーウィンドウが閉じられることです。これはおそらく悪い考えです。しかし、これが必要な理由については、Kevの投稿を参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.