如果修改或添加环境变量,则必须重新启动命令提示符。是否有一个命令,我可以执行,将这样做而不重新启动CMD?
当前回答
尝试以管理员身份打开一个新的命令提示符。我在Windows 10上使用了这个方法。(我知道这是一个老答案,但我不得不分享这个,因为不得不为这个写VBS脚本是荒谬的)。
其他回答
就像凯文说的,没有捷径可走。在大多数情况下,生成另一个CMD框更简单。更令人恼火的是,正在运行的程序也不知道这些变化(尽管IIRC可能有一个广播消息来查看此类变化的通知)。
更糟糕的是:在旧版本的Windows中,你必须先注销,然后再重新登录,才能考虑到这些变化……
使用“setx”并重新启动cmd提示符
有一个名为“setx”的命令行工具用于此作业。 它用于读取和写入env变量。 这些变量在命令窗口关闭后仍然存在。
创建或修改用户或系统环境中的环境变量,而不需要编程或脚本。setx命令还检索注册表项的值,并将它们写入文本文件。
注意:通过此工具创建或修改的变量将在以后的命令窗口中可用,但在当前CMD.exe命令窗口中不可用。所以,你必须重新开始。
如果缺少setx:
http://download.microsoft.com/download/win2000platform/setx/1.00.0.1/nt5/en-us/setx_setup.exe
或修改注册表
MSDN说:
若要以编程方式添加或修改系统环境变量,请使用add 他们去 HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ \控制会话 Manager\Environment注册表项,然后广播一个WM_SETTINGCHANGE 消息,lParam设置为字符串“环境”。 这允许应用程序(如shell)接收您的更新。
我喜欢巧克力之后的方法,就像匿名懦夫的回答,因为这是一个纯粹的批量处理方法。但是,它会留下一个临时文件和一些临时变量。我给自己做了一个更干净的版本。
在路径的某个地方创建一个文件refreshv .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.
可以通过在指定进程本身中覆盖环境表来实现这一点。
作为概念的证明,我写了这个示例应用程序,它只是在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的答案所记录的那样),并将整个环境表写入目标进程的内存中。
Edit: The size of the environment block is also stored in the _RTL_USER_PROCESS_PARAMETERS struct, but the memory is allocated on the process' heap. So from an external process we wouldn't have the ability to resize it and make it larger. I played around with using VirtualAllocEx to allocate additional memory in the target process for the environment storage, and was able to set and read an entirely new table. Unfortunately any attempt to modify the environment from normal means will crash and burn as the address no longer points to the heap (it will crash in RtlSizeHeap).
编辑:只有当您所做的环境更改是运行批处理文件的结果时,这才有效。
如果批处理文件以SETLOCAL开始,那么即使您在批处理退出前忘记调用ENDLOCAL,或者它意外中止,它也总是会在退出时解开回到原始环境。
几乎我编写的每个批处理文件都是从SETLOCAL开始的,因为在大多数情况下,我不希望环境更改的副作用仍然存在。在某些情况下,我确实希望某些环境变量的变化传播到批处理文件之外,那么我的最后一个ENDLOCAL看起来像这样:
ENDLOCAL & (
SET RESULT1=%RESULT1%
SET RESULT2=%RESULT2%
)
推荐文章
- GIT克隆在windows中跨本地文件系统回购
- 如何在POM.xml中引用环境变量?
- 如何运行一个PowerShell脚本而不显示窗口?
- PowerShell:仅为单个命令设置环境变量
- 为什么这个Windows批处理文件只执行第一行,而在命令shell中执行所有三行?
- 环境变量存储在Windows注册表的哪里?
- 有一个好的Valgrind Windows的替代品吗?
- 从Docker容器获取环境变量
- Windows和Linux上的c++编译:ifdef开关
- 如何验证批处理文件中是否存在一个文件?
- 在OSX中永久设置PATH环境变量
- 如何在Ubuntu中设置Java环境路径
- 异步运行Windows批处理文件命令
- XAMPP -端口80被PID 4的“无法打开进程”使用!12
- 如何在Linux中永久导出变量?