環境変数を変更または追加した場合、コマンドプロンプトを再起動する必要があります。CMDを再起動せずにこれを実行できるコマンドはありますか?
環境変数を変更または追加した場合、コマンドプロンプトを再起動する必要があります。CMDを再起動せずにこれを実行できるコマンドはありますか?
回答:
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"
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 .
RefreshEnv
して、更新された環境変数を現在のセッションに取り込むことができます。
Powershell
ますか?それcmd.exe
は私にとってはうまくいくようです。
Windows 7/8/10では、この組み込みのスクリプトを含むChocolateyをインストールできます。
Chocolateyをインストールしたら、と入力しrefreshenv
ます。
設計上、Windowsが別のcmd.exeから、または「マイコンピュータ->プロパティ->詳細設定->」から、すでに実行中のcmd.exeに環境変数の追加/変更/削除を伝達するための組み込みのメカニズムはありません。環境変数"。
既存のオープンコマンドプロンプトの範囲外で新しい環境変数を変更または追加する場合は、コマンドプロンプトを再起動するか、既存のコマンドプロンプトでSETを使用して手動で追加する必要があります。
最新の受け入れ答えを示して手動でリフレッシュすることにより、部分の周りの仕事のすべてのスクリプトで環境変数を。このスクリプトは、「マイコンピュータ...環境変数」で環境変数をグローバルに変更するユースケースを処理しますが、あるcmd.exeで環境変数が変更された場合、スクリプトは実行中の別のcmd.exeにそれを伝播しません。
最終的にはより簡単な解決策を見つける前に、私はこの答えに出くわしました。
explorer.exe
タスクマネージャで再起動するだけです。
テストはしませんでしたが、コマンドプロンプトを再度開く必要がある場合もあります。
功績ティモHuovinenここでは:正常にインストールがノードが認識されない(これはあなたを助けている場合、この人のコメントを信用を与える行ってください)。
cmd
管理者としてウィンドウを起動します。コマンドを使用しtaskkill /f /im explorer.exe && explorer.exe
ます。これにより、explorer.exeプロセスが強制終了され、再起動されます。
これはWindows 7で機能します。 SET PATH=%PATH%;C:\CmdShortcuts
echo%PATH%と入力してテストしましたが、うまくいきました。また、新しいcmdを開いた場合も設定されます。これらの厄介な再起動は不要です:)
setx
は、変更された変数があり、永続的に必要な変数がない可能性がある現在の環境を継承するためです。このようにすることで、変数を使用するためにコンソールを再起動する必要がなくなり、将来的に変数をグローバルに使用できなくなるという問題を回避できます。
「setx」を使用してコマンドプロンプトを再起動します
このジョブには、「setx」というコマンドラインツールがあります。これは、 env変数を読み書きするためのものです。変数は、コマンドウィンドウが閉じられた後も存続します。
これは、「プログラミングやスクリプトを必要とせずに、ユーザーまたはシステム環境で環境変数を作成または変更します。setxコマンドは、レジストリキーの値を取得し、それらをテキストファイルに書き込みます。」
注:このツールで作成または変更された変数は、将来のコマンドウィンドウで使用できますが、現在のCMD.exeコマンドウィンドウでは使用できません。したがって、再起動する必要があります。
ない場合setx
:
またはレジストリを変更します
MSDNは言う:
プログラムでシステム環境変数を追加または変更するには、それらをHKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ Environmentレジストリキーに追加してから、 lParamが文字列 " Environment "に設定されたWM_SETTINGCHANGE メッセージをブロードキャストします。
これにより、シェルなどのアプリケーションが更新を取得できます。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\VARIABLE
現在のユーザー環境: HKEY_CURRENT_USER\Environment\VARIABLE
%PATH%
、その後setx
1024バイトにこれを切り捨てることがあります!そしてちょうどそのように、彼の夕方は消えました
この関数を呼び出すとうまくいきました:
VOID Win32ForceSettingsChange()
{
DWORD dwReturnValue;
::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
私が思いついた最善の方法は、単にレジストリクエリを実行することでした。これが私の例です。
私の例では、新しい環境変数を追加したバッチファイルを使用してインストールを行いました。インストールが完了するとすぐにこれで何かをする必要がありましたが、これらの新しい変数を使用して新しいプロセスを生成できませんでした。別のエクスプローラーウィンドウの起動をテストして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
現在のセッションで再起動せずに変数をパスに追加する最も簡単な方法は、コマンドプロンプトを開いて次のように入力することです。
PATH=(VARIABLE);%path%
そして押す enterます。
変数が読み込まれたかどうかを確認するには、次のように入力します。
PATH
を押しenterます。ただし、再起動するまで、変数はパスの一部のみになります。
指定されたプロセス自体の中で環境テーブルを上書きすることにより、これを行うことができます。
概念実証として、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でクラッシュします)。
環境変数はHKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Session Manager \ Environmentに保持されます。
Pathなどの便利な環境変数の多くは、REG_SZとして格納されます。REGEDITを含むレジストリにアクセスするには、いくつかの方法があります。
REGEDIT /E <filename> "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
混乱を招くのは、コマンドを開始する場所がいくつかあることです。私の場合、私は走ったWindowsエクスプローラからcmdをと環境変数が変更されていない起動時にしながら、「ファイル名を指定して実行」から、CMD(Windowsキー+ rを)環境変数が変更されました。
私の場合、タスクマネージャーからWindowsエクスプローラープロセスを強制終了し、タスクマネージャーから再起動する必要がありました。
これを実行すると、Windowsエクスプローラーから生成されたコマンドから新しい環境変数にアクセスできました。
バッチスクリプトで次のコードを使用します。
if not defined MY_ENV_VAR (
setx MY_ENV_VAR "VALUE" > nul
set MY_ENV_VAR=VALUE
)
echo %MY_ENV_VAR%
使用してSETをした後、SETXコマンドウィンドウを再起動せずに、直接「ローカル」変数を使用することが可能です。そして、次の実行では、環境変数が使用されます。
匿名の臆病者の回答に投稿されているように、チョコレートに続くアプローチが好きでした。これは、純粋なバッチアプローチであるためです。ただし、一時ファイルといくつかの一時変数が残ります。自分用にクリーナーバージョンを作りました。
の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.
変更したい特定の1つ(またはいくつか)の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にはありません...
私が数年間使用してきたソリューション:
@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
編集:おっと、ここに更新されたバージョンがあります。
この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%"
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スクリプトで必要なすべてのタスクを実行します。
編集:これは、実行している環境の変更がバッチファイルの実行の結果である場合にのみ機能します。
バッチファイルがで始まる場合は、バッチが終了する前SETLOCAL
に呼び出しを忘れたENDLOCAL
場合や、バッチが予期せずに中止された場合でも、終了時に常に元の環境に戻ります。
ほとんどのSETLOCAL
場合、環境の変更による影響を残したくないので、ほとんどすべてのバッチファイルは最初から作成します。特定の環境変数の変更をバッチファイルの外に反映させたい場合、最後のファイルはENDLOCAL
次のようになります。
ENDLOCAL & (
SET RESULT1=%RESULT1%
SET RESULT2=%RESULT2%
)
これを解決するために、setxとsetの両方を使用して環境変数を変更し、explorer.exeのすべてのインスタンスを再起動しました。このようにして、その後に開始されたプロセスはすべて新しい環境変数を持ちます。
これを行うための私のバッチスクリプト:
setx /M ENVVAR "NEWVALUE"
set ENVVAR="NEWVALUE"
taskkill /f /IM explorer.exe
start explorer.exe >nul
exit
このアプローチの問題は、現在開かれているすべてのエクスプローラーウィンドウが閉じられることです。これはおそらく悪い考えです。しかし、これが必要な理由については、Kevの投稿を参照してください