如果修改或添加环境变量,则必须重新启动命令提示符。我是否可以执行一个无需重启CMD即可执行的命令?
如果修改或添加环境变量,则必须重新启动命令提示符。我是否可以执行一个无需重启CMD即可执行的命令?
Answers:
您可以使用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
道歉:
我提出此解决方案的两个主要问题是
一个。我找不到将vbs脚本中的环境变量导出回命令提示符的简单方法,并且
b。PATH环境变量是用户和系统PATH变量的串联。
我不确定用户和系统之间的变量冲突的一般规则是什么,因此我选择使用户覆盖系统,但专门处理的PATH变量除外。
我使用奇怪的vbs + bat + tempor bat机制来解决从vbs导出变量的问题。
注意:此脚本不会删除变量。
这可能可以改善。
添加
如果您需要将环境从一个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”并重新启动cmd提示符
有一个名为“ setx ” 的命令行工具可用于此作业。用于阅读和写作变量。关闭命令窗口后,变量仍然存在。
它“无需编程或编写脚本即可在用户或系统环境中创建或修改环境变量。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上,资源管理器仅作为单个实例运行,并且通常以登录用户身份运行。由于我需要管理员权限才能自动执行操作,因此失败无论从本地系统运行还是以管理员身份运行,都可以执行此操作。这样做的局限性在于它不能处理路径之类的问题,只能用于简单的环境变量。这使我可以使用批处理转到目录(包含空格)并复制运行.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
我还从各种不同的想法中想到了另一种方法。请看下面。基本上,这将从注册表中获取最新的路径变量,但是,这将导致许多问题,因为注册表查询本身将提供变量,这意味着到处都有变量将不起作用,因此请解决这个问题基本上使路径加倍。真讨厌 更合适的方法是:设置路径=%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。通过在调试器(例如WinDbg dt _PEB
和dt _RTL_USER_PROCESS_PARAMETERS
)中转储_PEB和_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\"
因此,如果您只想使用系统属性中的内容刷新当前命令会话中的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( 回声“无法将注册表写入临时位置” 1号出口 ) SETLOCAL EnableDelayedExpansion 为/ f“令牌= 1,2 * delims ==” %% i in('type%temp%\ env.reg ^ | findstr -c:\“ Path \” =')做( 设置== %%〜j 回声!upath:\\ = \!>%temp%\ newpath ) 本地 为/ f“ tokens = *”(%temp%\ newpath)中的%% i,请设置path = %% i
我喜欢匿名胆小鬼的回答中所说的巧克力味紧随其后的方法,因为它是纯批处理方法。但是,它留下一个临时文件和一些临时变量。我为自己做了一个清洁的版本。
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.
如果仅涉及您要更改的一个(或几个)特定的变量,我认为最简单的方法是一种解决方法:只需在您的环境中以及当前的控制台会话中进行设置
我有这个简单的批处理脚本,可以将Maven从Java7更改为Java8(都是环境变量)批处理文件夹位于PATH变量中,因此我始终可以在控制台和环境中的JAVA_HOME 变量中调用“ j8 ”被更改:
j8.bat:
@echo off
set JAVA_HOME=%JAVA_HOME_8%
setx JAVA_HOME "%JAVA_HOME_8%"
到现在为止,我发现此方法最有效,最简单。您可能希望将其放在一个命令中,但是在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年(实际上,更新shell cmd也并不容易,因为它是如上所述的单个实例),因为在Windows中更新环境变量可以完成许多自动化任务而无需必须手动重新启动命令行。
例如,我们使用它来允许在我们定期重新安装的大量计算机上部署和配置软件。而且我必须承认,在部署软件期间必须重新启动命令行是非常不切实际的,并且将要求我们找到不一定令人愉快的解决方法。让我们解决我们的问题。我们进行如下。
1-我们有一个批处理脚本,该脚本依次调用这样的powershell脚本
[文件:task.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脚本将继续执行其他任务。现在,要记住的一件事是,在任务完成之后,即使powershell脚本已在其自己的会话中更新了这些环境变量,cmd仍然无法访问新的环境变量。这就是为什么我们在powershell脚本中执行所有必需的任务的原因,这些脚本可以调用与cmd当然相同的命令。