593

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

4

26 に答える 26

149

vbs スクリプトを使用してシステム環境変数を取得できますが、現在の環境変数を実際に変更するにはバット スクリプトが必要であるため、これは組み合わせたソリューションです。

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 つの主な問題は次のとおりです。

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

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

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

vbs から変数をエクスポートする際の問題を回避するために、奇妙な vbs+bat+temporary bat メカニズムを使用します。

: このスクリプトは変数を削除しません。

これはおそらく改善される可能性があります。

追加した

あるコマンド ウィンドウから別のコマンド ウィンドウに環境をエクスポートする必要がある場合は、次のスクリプトを使用します (名前を付けましょう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"
于 2008-10-05T09:10:28.247 に答える
144

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 "RefreshEnv.cmd only works from cmd.exe, please install the Chocolatey Profile to take advantage of refreshenv from PowerShell"
echo | set /p dummy="Refreshing environment variables from registry for cmd.exe. 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

    :: capture user / architecture
    SET "OriginalUserName=%USERNAME%"
    SET "OriginalArchitecture=%PROCESSOR_ARCHITECTURE%"

    :: Set these variables
    call "%TEMP%\_env.cmd"

    :: Cleanup
    del /f /q "%TEMP%\_env.cmd" 2>nul

    :: reset user / architecture
    SET "USERNAME=%OriginalUserName%"
    SET "PROCESSOR_ARCHITECTURE=%OriginalArchitecture%"

    echo | set /p dummy="Finished."
    echo .
于 2015-09-06T06:01:33.660 に答える
68

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

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

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

于 2008-10-05T06:55:40.157 に答える
29

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

echo %PATH% と入力してテストしたところ、うまくいきました。また、新しいコマンドを開いた場合にも設定します。これらの厄介な再起動はもう必要ありません:)

于 2012-01-26T09:37:44.087 に答える
24

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

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

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

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

setx欠落している場合:


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

MSDNによると:

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

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

于 2012-08-14T15:38:38.403 に答える
15

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

VOID Win32ForceSettingsChange()
{
    DWORD dwReturnValue;
    ::SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
}
于 2010-03-19T18:15:39.027 に答える
11

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

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

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

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
于 2012-06-21T21:36:20.570 に答える
6

管理者として新しいコマンド プロンプトを開いてみます。これは Windows 10 でうまくいきました。

于 2015-12-22T20:53:58.363 に答える
6

環境変数は、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

    for /f "tokens=1,2* delims==" %%i in ('type %temp%\env.reg ^| findstr -c:\"Path\"=') do (
       set uppath=%%~j
       echo !upath:\\=\! >%temp%\新しいパス
       )

     エンドローカル

     for /f "tokens=*" %%i in (%temp%\newpath) do set path=%%i
于 2011-02-24T22:05:32.223 に答える
4

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

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

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

于 2014-05-21T08:32:29.613 に答える
4

私が数年前から使用しているソリューション:

@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

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

于 2019-11-27T07:38:18.223 に答える
3

次のような多くの問題を解決する、cmd と cygwin の Chocolatey refreshenv のより良い代替手段を作成しました。

  • 変数にいくつかの cmd メタ文字がある場合、 Chocolatey refreshenvは非常に悪いです。次のテストを参照してください。

    これを HKCU\Environment: のパスに追加しtest & echo baaaaaaaaaad、chocolatey を実行すると、非常に悪いrefreshenv出力が表示 baaaaaaaaaadされ、新しいパスがパス変数に追加されないことがわかります。

    このスクリプトはこれを解決し、次のような非常に悪いものであっても、任意のメタ文字でテストできます。

    ; & % ' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
    
  • refreshenv はシステムユーザー の環境変数のみを追加しますが、CMD は揮発性変数も追加します (HKCU\Volatile Environment)。このスクリプトは 3 つすべてをマージし、 重複を削除します

  • refreshenv で PATH をリセットします。このスクリプトは、このスクリプトを呼び出した親スクリプトの古いパスに新しいパスを追加します。古いパスを上書きするよりも優れています。そうしないと、親スクリプトによって新しく追加されたパスが削除されます。

  • このスクリプトは、@Gene Mayevsky によるコメントで説明されているこの問題を解決します。refreshenv は、環境変数 TEMP および TMP を変更し、それらを HKCU\Environment に格納されている値に置き換えます。私の場合、スクリプトを実行して、SYSTEM アカウントで実行されているスレーブで Jenkins ジョブによって変更された環境変数を更新するため、TEMP と TMP は C:\Windows\Temp ではなく %USERPROFILE%\AppData\Local\Temp に置き換えられます。これにより、リンカがシステム プロファイルの Temp フォルダを開くことができないため、ビルドが中断されます。

cmd 用に 1 つのスクリプトを作成し、cygwin/bash 用に別のスクリプトを作成しました

コマンドの場合

このスクリプトは vbscript を使用しているため、すべての Windows バージョンxp以降で動作します。

それを使用するには、refrenv.batとして保存し、次のように呼び出します。call refrenv.bat

<!-- : Begin batch script
@echo off
REM PUSHD "%~dp0"


REM author: Badr Elmers 2021
REM description: refrenv = refresh environment. this is a better alternative to the chocolatey refreshenv for cmd
REM https://github.com/badrelmers/RefrEnv
REM https://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w

REM ___USAGE_____________________________________________________________
REM usage: 
REM        call refrenv.bat        full refresh. refresh all non critical variables*, and refresh the PATH

REM debug:
REM        to debug what this script do create this variable in your parent script like that
REM        set debugme=yes
REM        then the folder containing the files used to set the variables will be open. Then see
REM        _NewEnv.cmd this is the file which run inside your script to setup the new variables, you
REM        can also revise the intermediate files _NewEnv.cmd_temp_.cmd and _NewEnv.cmd_temp2_.cmd 
REM        (those two contains all the variables before removing the duplicates and the unwanted variables)


REM you can also put this script in windows\systems32 or another place in your %PATH% then call it from an interactive console by writing refrenv

REM *critical variables: are variables which belong to cmd/windows and should not be refreshed normally like:
REM - windows vars:
REM ALLUSERSPROFILE APPDATA CommonProgramFiles CommonProgramFiles(x86) CommonProgramW6432 COMPUTERNAME ComSpec HOMEDRIVE HOMEPATH LOCALAPPDATA LOGONSERVER NUMBER_OF_PROCESSORS OS PATHEXT PROCESSOR_ARCHITECTURE PROCESSOR_ARCHITEW6432 PROCESSOR_IDENTIFIER PROCESSOR_LEVEL PROCESSOR_REVISION ProgramData ProgramFiles ProgramFiles(x86) ProgramW6432 PUBLIC SystemDrive SystemRoot TEMP TMP USERDOMAIN USERDOMAIN_ROAMINGPROFILE USERNAME USERPROFILE windir SESSIONNAME


REM ___INFO_____________________________________________________________
REM :: this script reload environment variables inside cmd every time you want environment changes to propagate, so you do not need to restart cmd after setting a new variable with setx or when installing new apps which add new variables ...etc


REM This is a better alternative to the chocolatey refreshenv for cmd, which solves a lot of problems like:

REM The Chocolatey refreshenv is so bad if the variable have some cmd meta-characters, see this test:
    REM add this to the path in HKCU\Environment: test & echo baaaaaaaaaad, and run the chocolatey refreshenv you will see that it prints baaaaaaaaaad which is very bad, and the new path is not added to your path variable.
    REM This script solve this and you can test it with any meta-character, even something so bad like:
    REM ; & % ' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
    
REM refreshenv adds only system and user environment variables, but CMD adds volatile variables too (HKCU\Volatile Environment). This script will merge all the three and remove any duplicates.

REM refreshenv reset your PATH. This script append the new path to the old path of the parent script which called this script. It is better than overwriting the old path, otherwise it will delete any newly added path by the parent script.

REM This script solve this problem described in a comment by @Gene Mayevsky: refreshenv modifies env variables TEMP and TMP replacing them with values stored in HKCU\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that's running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\AppData\Local\Temp instead of C:\Windows\Temp. This breaks build because linker cannot open system profile's Temp folder.

REM ________
REM this script solve things like that too:
REM The confusing thing might be that there are a few places to start the cmd from. In my case I run cmd from windows explorer and the environment variables did not change while when starting cmd from the "run" (windows key + r) the environment variables were changed.

REM In my case I just had to kill the windows explorer process from the task manager and then restart it again from the task manager.
REM Once I did this I had access to the new environment variable from a cmd that was spawned from windows explorer.

REM my conclusion:
REM if I add a new variable with setx, i can access it in cmd only if i run cmd as admin, without admin right i have to restart explorer to see that new variable. but running this script inside my script (who sets the variable with setx) solve this problem and i do not have to restart explorer


REM ________
REM windows recreate the path using three places at less:
REM the User namespace:    HKCU\Environment
REM the System namespace:  HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
REM the Session namespace: HKCU\Volatile Environment
REM but the original chocolatey script did not add the volatile path. This script will merge all the three and remove any duplicates. this is what windows do by default too

REM there is this too which cmd seems to read when first running, but it contains only TEMP and TMP,so i will not use it
REM HKEY_USERS\.DEFAULT\Environment


REM ___TESTING_____________________________________________________________
REM to test this script with extreme cases do
    REM :: Set a bad variable
    REM add a var in reg HKCU\Environment as the following, and see that echo is not executed.  if you use refreshenv of chocolatey you will see that echo is executed which is so bad!
    REM so save this in reg:
    REM all 32 characters: & % ' ( ) ~ + @ # $ { } [ ] ; , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
    REM and this:
    REM (^.*)(Form Product=")([^"]*") FormType="[^"]*" FormID="([0-9][0-9]*)".*$
    REM and use set to print those variables and see if they are saved without change ; refreshenv fail dramatically with those variables
    
    
REM invalid characters (illegal characters in file names) in Windows using NTFS
REM \ / : * ? "  < > |  and ^ in FAT 



REM __________________________________________________________________________________________
REM __________________________________________________________________________________________
REM __________________________________________________________________________________________
REM this is a hybrid script which call vbs from cmd directly
REM :: The only restriction is the batch code cannot contain - - > (without space between - - > of course)
REM :: The only restriction is the VBS code cannot contain </script>.
REM :: The only risk is the undocumented use of "%~f0?.wsf" as the script to load. Somehow the parser properly finds and loads the running .BAT script "%~f0", and the ?.wsf suffix mysteriously instructs CSCRIPT to interpret the script as WSF. Hopefully MicroSoft will never disable that "feature".
REM :: https://stackoverflow.com/questions/9074476/is-it-possible-to-embed-and-execute-vbscript-within-a-batch-file-without-using-a

if "%debugme%"=="yes" (
    echo RefrEnv - Refresh the Environment for CMD - ^(Debug enabled^)
) else (
    echo RefrEnv - Refresh the Environment for CMD
)

set "TEMPDir=%TEMP%\refrenv"
IF NOT EXIST "%TEMPDir%" mkdir "%TEMPDir%"
set "outputfile=%TEMPDir%\_NewEnv.cmd"


REM detect if DelayedExpansion is enabled
REM It relies on the fact, that the last caret will be removed only in delayed mode.
REM https://www.dostips.com/forum/viewtopic.php?t=6496
set "DelayedExpansionState=IsDisabled"
IF "^!" == "^!^" (
    REM echo DelayedExpansion is enabled
    set "DelayedExpansionState=IsEnabled"
)


REM :: generate %outputfile% which contain all the new variables
REM cscript //nologo "%~f0?.wsf" %1
cscript //nologo "%~f0?.wsf" "%outputfile%" %DelayedExpansionState%


REM ::set the new variables generated with vbscript script above
REM for this to work always it is necessary to use DisableDelayedExpansion or escape ! and ^ when using EnableDelayedExpansion, but this script already solve this, so no worry about that now, thanks to God
REM test it with some bad var like:
REM all 32 characters: ; & % ' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
REM For /f delims^=^ eol^= %%a in (%outputfile%) do %%a
REM for /f "delims== tokens=1,2" %%G in (%outputfile%) do set "%%G=%%H"
For /f delims^=^ eol^= %%a in (%outputfile%) do set %%a


REM for safely print a variable with bad charachters do:
REM SETLOCAL EnableDelayedExpansion
REM echo "!z9!"
REM or
REM set z9
REM but generally paths and environment variables should not have bad metacharacters, but it is not a rule!


if "%debugme%"=="yes" (
    explorer "%TEMPDir%"
) else (
    rmdir /Q /S "%TEMPDir%"
)

REM cleanup
set "TEMPDir="
set "outputfile="
set "DelayedExpansionState="
set "debugme="


REM pause
exit /b



REM #############################################################################
REM :: to run jscript you have to put <script language="JScript"> directly after ----- Begin wsf script --->
----- Begin wsf script --->
<job><script language="VBScript">
REM #############################################################################
REM ### put you code here #######################################################
REM #############################################################################

REM based on itsadok script from here
REM https://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w

REM and it is faster as stated by this comment
REM While I prefer the Chocolatey code-wise for being pure batch code, overall I decided to use this one, since it's faster. (~0.3 seconds instead of ~1 second -- which is nice, since I use it frequently in my Explorer "start cmd here" entry) – 

REM and it is safer based on my tests, the Chocolatey refreshenv is so bad if the variable have some cmd metacharacters


Const ForReading = 1 
Const ForWriting = 2
Const ForAppending = 8 

Set WshShell = WScript.CreateObject("WScript.Shell")
filename=WScript.Arguments.Item(0)
DelayedExpansionState=WScript.Arguments.Item(1)

TMPfilename=filename & "_temp_.cmd"
Set fso = CreateObject("Scripting.fileSystemObject")
Set tmpF = fso.CreateTextFile(TMPfilename, TRUE)


set oEnvS=WshShell.Environment("System")
for each sitem in oEnvS
    tmpF.WriteLine(sitem)
next
SystemPath = oEnvS("PATH")

set oEnvU=WshShell.Environment("User")
for each sitem in oEnvU
    tmpF.WriteLine(sitem)
next
UserPath = oEnvU("PATH")

set oEnvV=WshShell.Environment("Volatile")
for each sitem in oEnvV
    tmpF.WriteLine(sitem)
next
VolatilePath = oEnvV("PATH")

set oEnvP=WshShell.Environment("Process")
REM i will not save the process env but only its path, because it have strange variables like  =::=::\ and  =F:=.... which seems to be added by vbscript
REM for each sitem in oEnvP
    REM tmpF.WriteLine(sitem)
REM next
REM here we add the actual session path, so we do not reset the original path, because maybe the parent script added some folders to the path, If we need to reset the path then comment the following line
ProcessPath = oEnvP("PATH")

REM merge System, User, Volatile, and process PATHs
NewPath = SystemPath & ";" & UserPath & ";" & VolatilePath & ";" & ProcessPath


REM ________________________________________________________________
REM :: remove duplicates from path
REM :: expand variables so they become like windows do when he read reg and create path, then Remove duplicates without sorting 
    REM why i will clean the path from duplicates? because:
    REM the maximum string length in cmd is 8191 characters. But string length doesnt mean that you can save 8191 characters in a variable because also the assignment belongs to the string. you can save 8189 characters because the remaining 2 characters are needed for "a="
   
    REM based on my tests: 
    REM when i open cmd as user , windows does not remove any duplicates from the path, and merge system+user+volatil path
    REM when i open cmd as admin, windows do: system+user path (here windows do not remove duplicates which is stupid!) , then it adds volatil path after removing from it any duplicates 

REM ' https://www.rosettacode.org/wiki/Remove_duplicate_elements#VBScript
Function remove_duplicates(list)
    arr = Split(list,";")
    Set dict = CreateObject("Scripting.Dictionary")
    REM ' force dictionary compare to be case-insensitive , uncomment to force case-sensitive
    dict.CompareMode = 1

    For i = 0 To UBound(arr)
        If dict.Exists(arr(i)) = False Then
            dict.Add arr(i),""
        End If
    Next
    For Each key In dict.Keys
        tmp = tmp & key & ";"
    Next
    remove_duplicates = Left(tmp,Len(tmp)-1)
End Function
 
REM expand variables
NewPath = WshShell.ExpandEnvironmentStrings(NewPath)
REM remove duplicates
NewPath=remove_duplicates(NewPath)

REM remove_duplicates() will add a ; to the end so lets remove it if the last letter is ;
If Right(NewPath, 1) = ";" Then 
    NewPath = Left(NewPath, Len(NewPath) - 1) 
End If
  
tmpF.WriteLine("PATH=" & NewPath)
tmpF.Close

REM ________________________________________________________________
REM :: exclude setting variables which may be dangerous to change

    REM when i run a script from task scheduler using SYSTEM user the following variables are the differences between the scheduler env and a normal cmd script, so i will not override those variables
    REM APPDATA=D:\Users\LLED2\AppData\Roaming
    REM APPDATA=D:\Windows\system32\config\systemprofile\AppData\Roaming

    REM LOCALAPPDATA=D:\Users\LLED2\AppData\Local
    REM LOCALAPPDATA=D:\Windows\system32\config\systemprofile\AppData\Local

    REM TEMP=D:\Users\LLED2\AppData\Local\Temp
    REM TEMP=D:\Windows\TEMP

    REM TMP=D:\Users\LLED2\AppData\Local\Temp
    REM TMP=D:\Windows\TEMP

    REM USERDOMAIN=LLED2-PC
    REM USERDOMAIN=WORKGROUP

    REM USERNAME=LLED2
    REM USERNAME=LLED2-PC$

    REM USERPROFILE=D:\Users\LLED2
    REM USERPROFILE=D:\Windows\system32\config\systemprofile

    REM i know this thanks to this comment
    REM The solution is good but it modifies env variables TEMP and TMP replacing them with values stored in HKCU\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that's running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\AppData\Local\Temp instead of C:\Windows\Temp. This breaks build because linker cannot open system profile's Temp folder. – Gene Mayevsky Sep 26 '19 at 20:51


REM Delete Lines of a Text File Beginning with a Specified String
REM those are the variables which should not be changed by this script 
arrBlackList = Array("ALLUSERSPROFILE=", "APPDATA=", "CommonProgramFiles=", "CommonProgramFiles(x86)=", "CommonProgramW6432=", "COMPUTERNAME=", "ComSpec=", "HOMEDRIVE=", "HOMEPATH=", "LOCALAPPDATA=", "LOGONSERVER=", "NUMBER_OF_PROCESSORS=", "OS=", "PATHEXT=", "PROCESSOR_ARCHITECTURE=", "PROCESSOR_ARCHITEW6432=", "PROCESSOR_IDENTIFIER=", "PROCESSOR_LEVEL=", "PROCESSOR_REVISION=", "ProgramData=", "ProgramFiles=", "ProgramFiles(x86)=", "ProgramW6432=", "PUBLIC=", "SystemDrive=", "SystemRoot=", "TEMP=", "TMP=", "USERDOMAIN=", "USERDOMAIN_ROAMINGPROFILE=", "USERNAME=", "USERPROFILE=", "windir=", "SESSIONNAME=")

Set objFS = CreateObject("Scripting.FileSystemObject")
Set objTS = objFS.OpenTextFile(TMPfilename, ForReading)
strContents = objTS.ReadAll
objTS.Close

TMPfilename2= filename & "_temp2_.cmd"
arrLines = Split(strContents, vbNewLine)
Set objTS = objFS.OpenTextFile(TMPfilename2, ForWriting, True)

REM this is the equivalent of findstr /V /I /L  or  grep -i -v  , i don t know a better way to do it, but it works fine
For Each strLine In arrLines
    bypassThisLine=False
    For Each BlackWord In arrBlackList
        If Left(UCase(LTrim(strLine)),Len(BlackWord)) = UCase(BlackWord) Then
            bypassThisLine=True
        End If
    Next
    If bypassThisLine=False Then
        objTS.WriteLine strLine
    End If
Next

REM ____________________________________________________________
REM :: expand variables because registry save some variables as unexpanded %....%
REM :: and escape ! and ^ for cmd EnableDelayedExpansion mode

set f=fso.OpenTextFile(TMPfilename2,ForReading)
REM Write file:  ForAppending = 8 ForReading = 1 ForWriting = 2 , True=create file if not exist
set fW=fso.OpenTextFile(filename,ForWriting,True)
Do Until f.AtEndOfStream
    LineContent = f.ReadLine
    REM expand variables
    LineContent = WshShell.ExpandEnvironmentStrings(LineContent)
    
    REM _____this part is so important_____
    REM if cmd delayedexpansion is enabled in the parent script which calls this script then bad thing happen to variables saved in the registry if they contain ! . if var have ! then ! and ^ are removed; if var do not have ! then ^ is not removed . to understand what happens read this :
    REM how cmd delayed expansion parse things
    REM https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912
    REM For each parsed token, first check if it contains any !. If not, then the token is not parsed - important for ^ characters. If the token does contain !, then scan each character from left to right:
    REM     - If it is a caret (^) the next character has no special meaning, the caret itself is removed
    REM     - If it is an exclamation mark, search for the next exclamation mark (carets are not observed anymore), expand to the value of the variable.
    REM         - Consecutive opening ! are collapsed into a single !
    REM         - Any remaining unpaired ! is removed
    REM ...
    REM Look at next string of characters, breaking before !, :, or <LF>, and call them VAR

    REM conclusion:
    REM when delayedexpansion is enabled and var have ! then i have to escape ^ and ! ,BUT IF VAR DO NOT HAVE ! THEN DO NOT ESCAPE ^  .this made me crazy to discover
    REM when delayedexpansion is disabled then i do not have to escape anything
    
    If DelayedExpansionState="IsEnabled" Then
        If InStr(LineContent, "!") > 0 Then
            LineContent=Replace(LineContent,"^","^^")
            LineContent=Replace(LineContent,"!","^!")
        End If
    End If
    REM __________
    
    fW.WriteLine(LineContent)
Loop

f.Close
fW.Close

REM #############################################################################
REM ### end of vbscript code ####################################################
REM #############################################################################
REM this must be at the end for the hybrid trick, do not remove it
</script></job>


cygwin/bash の場合:

ここには投稿できません 投稿制限に達しましたので、こちらからダウンロードしてください

次のようにbashから呼び出します。source refrenv.sh

Powershell の場合:

ここからダウンロードしてください

次のコマンドを使用して、Powershell から呼び出します。. .\refrenv.ps1

于 2021-10-01T16:11:12.023 に答える
1

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

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

于 2008-10-05T14:17:35.303 に答える
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%"
于 2017-01-12T11:25:57.200 に答える
0

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

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

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

ENDLOCAL & (
  SET RESULT1=%RESULT1%
  SET RESULT2=%RESULT2%
)
于 2013-01-12T01:51:23.220 に答える
0

Anaconda を使用している方は、chocolateyRefreshenvコマンドを使用するときに、conda に関連付けられているすべての環境変数が失われます。これに対抗するには、CMD を再起動するのが最善の方法です。:(

于 2021-12-28T07:59:03.557 に答える
0

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

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

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

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

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

于 2015-04-27T08:45:40.303 に答える