web-dev-qa-db-ja.com

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

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

418
Eric Schoonover

システムの環境変数は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を実行してください。


謝罪

私がこの解決策を考え出していた2つの主な問題は

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

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

一般的な規則がユーザーとシステムの間で競合する変数にどのようなものがあるかわからないので、私は特にPATH変数を除いて、ユーザーがシステムをオーバーライドするように選択しました。

私は変なvbs + bat +一時的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"
127
itsadok

これはチョコレートが使用するものです。

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 .
85

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

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

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

55
Kev

窓7/8/10にあなたは作り付けこれのためのスクリプトを持っているChocolateyをインストールすることができます。

Chocolateyをインストールした後、引用符なしで "refreshenv"を入力してください。

45
jolly

これはWindows 7で動作します:SET PATH=%PATH%;C:\CmdShortcuts

echo%PATH%と入力してテストしましたが、うまくいきました。また、新しいcmdを開いたときに設定します。これらの面倒な再起動は不要です。

34

私は結局もっと簡単な解決策を見つける前にこの答えに出会いました。

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

私はテストしませんでしたが、あなたはまたあなたがコマンドプロンプトを開く必要があるかもしれません。

Timo Huovinen here: 正常にインストールされたにもかかわらずノードが認識されない (これがあなたの助けになった場合、この男性のコメントをください。

31
wharding28

"setx"を使用してcmdプロンプトを再起動します

この仕事のための " setx "という名前のコマンドラインツールがあります。 読み書き用 env変数です。変数はコマンドウィンドウが閉じられた後も持続します。

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

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

setxが見つからない場合:


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

MSDN の意味:

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

これにより、シェルなどのアプリケーションがアップデートを受け取ることができます。

25
Jens A. Koch

この関数を呼ぶことは私のために働きました:

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

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

私の例では、新しい環境変数を追加したバッチファイルを使用してインストールを行いました。インストールが完了したらすぐにこれを行う必要がありましたが、それらの新しい変数で新しいプロセスを生成することができませんでした。私は別のExplorerウィンドウを生成することをテストし、cmd.exeにコールバックしましたが、これはうまくいきました、しかしVistaとWindows 7では、Explorerは単一インスタンスとしてそして通常ログインした人として実行するだけです。ローカルシステムから実行しているかボックスの管理者として実行しているかに関係なく、物事をやる。これに対する制限は、それがパスのようなものを扱わないということです、これは単純な環境変数だけに働きました。これは私がディレクトリを取得するためにバッチを使用することを可能にしました(スペースで)そしてファイルにコピーする.exesなどを実行します。これは今日stackoverflow.comのmayリソースから書かれました

元のバッチが新しいバッチを呼び出します。

testenvget.cmd SDROOT(またはどんな変数でも)

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

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

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

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

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

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

さまざまなアイデアから思いついた別の方法もあります。下記を参照してください。これは基本的にレジストリから最新のパス変数を取得しますが、これはレジストリクエリがそれ自身で変数を与えようとしているために多くの問題を引き起こします。基本的に道を二倍にしなさい。非常に厄介です。より好ましい方法は次のとおりです。Set Path =%Path%; C:\ Program Files\Software .... \

これが新しいバッチファイルですが、注意してください。

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
set org=%PATH%
for /f "tokens=2*" %%A in ('REG QUERY "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path ^|FIND /I "Path"') DO (
SET path=%%B
)
SET PATH=%org%;%PATH%
set path
11

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

概念実証として、このサンプルアプリを作成しました。このサンプルアプリでは、cmd.exeプロセスで単一の(既知の)環境変数を編集しただけです。

typedef DWORD (__stdcall *NtQueryInformationProcessPtr)(HANDLE, DWORD, PVOID, ULONG, PULONG);

int __cdecl main(int argc, char* argv[])
{
    HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
    NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");

    int processId = atoi(argv[1]);
    printf("Target PID: %u\n", processId);

    // open the process with read+write access
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, processId);
    if(hProcess == NULL)
    {
        printf("Error opening process (%u)\n", GetLastError());
        return 0;
    }

    // find the location of the PEB
    PROCESS_BASIC_INFORMATION pbi = {0};
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
    if(status != 0)
    {
        printf("Error ProcessBasicInformation (0x%8X)\n", status);
    }
    printf("PEB: %p\n", pbi.PebBaseAddress);

    // find the process parameters
    char *processParamsOffset = (char*)pbi.PebBaseAddress + 0x20; // hard coded offset for x64 apps
    char *processParameters = NULL;
    if(ReadProcessMemory(hProcess, processParamsOffset, &processParameters, sizeof(processParameters), NULL))
    {
        printf("UserProcessParameters: %p\n", processParameters);
    }
    else
    {
        printf("Error ReadProcessMemory (%u)\n", GetLastError());
    }

    // find the address to the environment table
    char *environmentOffset = processParameters + 0x80; // hard coded offset for x64 apps
    char *environment = NULL;
    ReadProcessMemory(hProcess, environmentOffset, &environment, sizeof(environment), NULL);
    printf("environment: %p\n", environment);

    // copy the environment table into our own memory for scanning
    wchar_t *localEnvBlock = new wchar_t[64*1024];
    ReadProcessMemory(hProcess, environment, localEnvBlock, sizeof(wchar_t)*64*1024, NULL);

    // find the variable to edit
    wchar_t *found = NULL;
    wchar_t *varOffset = localEnvBlock;
    while(varOffset < localEnvBlock + 64*1024)
    {
        if(varOffset[0] == '\0')
        {
            // we reached the end
            break;
        }
        if(wcsncmp(varOffset, L"ENVTEST=", 8) == 0)
        {
            found = varOffset;
            break;
        }
        varOffset += wcslen(varOffset)+1;
    }

    // check to see if we found one
    if(found)
    {
        size_t offset = (found - localEnvBlock) * sizeof(wchar_t);
        printf("Offset: %Iu\n", offset);

        // write a new version (if the size of the value changes then we have to rewrite the entire block)
        if(!WriteProcessMemory(hProcess, environment + offset, L"ENVTEST=def", 12*sizeof(wchar_t), NULL))
        {
            printf("Error WriteProcessMemory (%u)\n", GetLastError());
        }
    }

    // cleanup
    delete[] localEnvBlock;
    CloseHandle(hProcess);

    return 0;
}

出力例:

>set ENVTEST=abc

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

>set ENVTEST
ENVTEST=def

ノート

このアプローチもセキュリティ上の制限に制限されます。ターゲットがより高い標高またはより高いアカウント(SYSTEMなど)で実行されている場合、そのメモリを編集する権限はありません。

32ビットアプリでこれを実行したい場合は、上記のハードコードされたオフセットはそれぞれ0x10と0x48に変更されます。これらのオフセットは、デバッガで_PEBおよび_RTL_USER_PROCESS_PARAMETERS構造体をダンプすることで見つけることができます(たとえば、WinDbg dt _PEBおよびdt _RTL_USER_PROCESS_PARAMETERS)。

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

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

7
josh poley

紛らわしいのは、cmdを開始する場所がいくつかあることです。私の場合、windows Explorerからのcmdおよび環境変数は変更されませんでしたを起動したときに"run"からのcmd(windowsキー+ r)環境変数が変更されました

私の場合、タスクマネージャーからWindowsエクスプローラープロセスを強制終了してから、タスクマネージャーから再起動するでした。

これを行うと、Windows Explorerから生成されたcmdから新しい環境変数にアクセスできました。

5

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

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

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

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

そのため、現在のコマンドセッションで、システムプロパティの内容でパス変数を更新したいだけであれば、次のバッチスクリプトは正常に機能します。

RefreshPath.cmd:

 
 @echo off 
 
 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"レジストリを一時的な場所に書き込めません "
 exit 1 
)
 
 SETLOCAL/f "トークンのEnableDelayedExpansion 
 
 = 1,2 * delims ==" %% i in( 'type% temp%\ env.reg ^ | findstr -c:\ "パス\" = ')do(
 set upath = %%〜j 
 echo!upath:\\ = \!>%/f "tokens = *" %% i in(%temp%\ newpath)の場合、temp%\ newpath 
 
 ENDLOCAL 
 
 path = %% iを設定します。
5
Algonaut

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

PATH=(VARIABLE);%path%

を押して enter

変数がロードされたかどうかを確認するには、次のように入力します。

PATH

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

4

管理者として新しいコマンドプロンプトを開きます。これはWindows 10で私のために働きました(私はこれが古い答えであることを知っています、しかしこれのためにVBSスクリプトを書かなければならないのでこれを共有しなければなりませんでした)。

4
estebro

エクスプローラを再起動することは私のためにこれをしました、しかし、新しいcmdターミナルのためだけに。

私がパスを設定した端末は、すでに新しいPath変数を見ることができました(Windows 7の場合)。

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

explorer.exeを再起動してください>>

3
SkyW3lker

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

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

_ set _ _ setx _ の後に使用すると、コマンドウィンドウを再起動せずに "local"変数を直接使用できます。そして次回の実行時には、環境変数が使用されます。

3
Sebastian

匿名の臆病者の答えに掲載されているように、私はアプローチの後にチョコレートが続くのが好きでした。それは純粋なバッチアプローチだからです。ただし、一時ファイルといくつかの一時変数が残っています。私は自分のためにもっときれいなバージョンを作りました。

PATHのどこかにファイルrefreshEnv.batを作成してください。 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

最初にchocoをインストールしてください。

  • 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"を使用している場合

  • powerShell Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))を使用している場合

それからrefreshenvを実行できます。 cmdとpowershellの両方で動作します。

2

それがあなたが変更したい1つ(またはいくつか)の特定の変数だけに関係しているなら、私は最も簡単な方法が 回避策 :あなたの環境にそしてあなたの現在のコンソールセッションに設定することだと思います

  • Setは現在のセッションに変数を入れます
  • SetXはvarを環境に置きますが、あなたの現在のセッションには入れません

私はMavenをJava 7からJava 8に変更するためのこの単純なバッチスクリプトを持っています(どちらもenv。varsです)。バッチフォルダはmy _ path _ varにありますので、 ' j8 と呼びます。 'そして私のコンソール内および環境内で、私のJava_HOME変数が変更されます。

j8.bat:

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

今まで、私はこれが最もうまくそして最も簡単に機能するのを見つけます。これを1つのコマンドにまとめたいと思うかもしれませんが、Windowsにはありません。

2

2019年でも非常に興味深いこの質問を投稿していただきありがとうございます(実際、シェルコマンドは上記のように単一のインスタンスであるため、シェルコマンドを更新するのは簡単ではありません)。手動でコマンドラインを再起動する必要があります。

たとえば、これを使用して、定期的に再インストールする多数のマシンにソフトウェアを展開および構成できるようにします。また、ソフトウェアの展開中にコマンドラインを再起動することは非常に非現実的であり、必ずしも快適ではない回避策を見つける必要があることを認めなければなりません。問題に取り掛かりましょう。次のように進めます。

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スクリプトで必要なタスクをすべて実行する理由です。

1
Andy McRae

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

さらに悪いことに、古いバージョンのWindowsでは、ログオフしてからログアウトして変更を反映させる必要がありました。

1
PhiLho

Windowsで環境変数を更新する必要がある場合は、PCを再起動するよりも端末からrefreshenvを実行します。

1
Jasper

この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
Iulian Dita

いいえ、そうは思いません…でも手動で設定できます。それで、あなたはそれらをバッチファイルか何かに入れることができます。

おそらく、レジストリにクエリを実行し、現在の環境を同じに設定するユーティリティ/スクリプトを作成することができます(まだ誰かがいない場合)。

0
Keith Nicholas

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

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

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

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