每个进程都有自己的环境变量列表。每次创建进程时,Windows 都会将新进程的正在运行进程的当前环境变量列表复制到单独的内存区域中。
子进程不能修改其父进程的环境变量,父进程也不能修改其子进程之一的环境变量。如果那是可能的,那就意味着任何进程都可以操纵任何其他进程的工作记忆,那肯定是不好的。
在命令提示符窗口中执行以下操作可以轻松查看环境变量管理:
title First CMD
set PATH
第一行将命令进程窗口的窗口标题更改为First CMD。
第二个命令列出所有以PATH 开头的环境变量及其值。这通常意味着环境变量PATH 和PATHEXT 的值与当前运行命令进程的环境变量列表中的值相同。
set "PATH=%PATH%;%USERPROFILE%\Desktop"
start "Second CMD"
第一行将您的桌面目录附加到 当前 命令进程的PATH。第二行再打开一个命令提示符窗口
带有窗口标题Second CMD。第二个命令进程获取当前命令进程的所有环境变量的副本。
在第二命令提示符窗口中运行:
set PATH
输出为PATHEXT 和PATH,最后包含您的桌面目录。因此,在这里已经可以看出,新的命令进程是使用与在启动第二个命令进程时为第一个命令进程定义的相同的环境变量创建的,而不是存储在 Windows 注册表中并在查看高级系统设置中的环境变量时显示的内容窗户。
切换到第一个命令提示符窗口并执行:
set PATH=
sort /?
结果是错误信息:
排序未被识别为内部或外部命令,
可运行的程序或批处理文件。
sort.exe in directory %SystemRoot%\System32 在此命令进程中不再被 Windows 命令解释器找到,因为 local PATH 以及用于搜索可执行文件和脚本的所有目录路径不再存在在这个命令过程中除了当前目录是偶然%SystemRoot%\System32。
在第一个命令提示符窗口中运行:
start "Third CMD"
在打开的第三个命令提示符窗口中运行:
set PATH
列出的只有 PATHEXT 及其值。 PATH 在第一个命令提示符窗口中不再定义,因此在第三个命令提示符窗口中也不存在。
在第三个命令提示符窗口中运行:
set PATH=%SystemRoot%\System32
sort /?
外部命令 SORT 的帮助显示为可执行文件可以被 Windows 命令解释器在第三个命令进程中找到,因为 local PATH 被再次定义包含sort.exe的目录的路径。
切换到第二个命令提示符窗口并运行:
sort /?
外部命令 SORT 的帮助也会显示在第二个命令提示符窗口中,因为 local PATH 仍然具有启动它时的所有目录路径,包括您的桌面文件夹最后。
切换到第一个命令提示符窗口并运行:
sort /?
之前删除后仍然显示第一个命令提示窗口PATH未定义的错误消息。
所以现在有 3 个命令进程正在运行
- 根本没有定义
PATH,
-
PATH 带有未存储在 Windows 注册表中的其他桌面文件夹,
-
PATH 很可能只有 C:\Windows\System32 作为唯一的文件夹路径。
您现在还可以在 Windows 高级系统设置中的 user 或 system 环境变量列表中修改 PATH,但这不会改变 3 上的任何内容本地 PATH 3 个已经运行的命令进程。
现在关闭所有 3 个不再需要的命令进程窗口。
查看What is the reason for 'sort' is not recognized as an internal or external command, operable program or batch file? 上的答案,它解释了 system 和 user PATH 在 Windows 注册表中的存储位置。
我假设 setup.exe 运行首先将目录路径直接添加到 Windows 注册表中的 system 或 user PATH 这仅对从 Windows 桌面启动的新进程有效或开始菜单,但不适用于任何已经运行的进程。
因此您必须在批处理文件中执行您已经在 PowerShell 脚本中执行的操作,直接从 Windows 注册表中查询 PATH 的值并为命令进程设置 local PATH当前正在执行批处理文件。
@echo off
rem Get directly from Windows registry the system PATH variable value.
set "SystemPath="
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do (
if /I "%%N" == "Path" (
set "SystemPath=%%P"
goto GetUserPath
)
)
rem Get directly from Windows registry the user PATH variable value.
:GetUserPath
set "UserPath="
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKCU\Environment" /v "Path" 2^>nul') do (
if /I "%%N" == "Path" (
set "UserPath=%%P"
goto SetPath
)
)
rem Concatenate the two PATH values to a single value and expand variables.
rem Delete the two environment variables not further needed.
rem Next replace all two consecutive semicolons by a single semicolon.
rem Last remove semicolon from end of directory list if there is one.
:SetPath
call set "PATH=%SystemPath%;%UserPath%"
set "SystemPath="
set "UserPath="
set "PATH=%PATH:;;=;%"
if "%PATH:~-1%" == ";" set "PATH=%PATH:~0,-1%"
如果目录路径列表中有;; 或目录路径列表以; 结尾,则最后两个命令实际上不是必需的。
以上批处理代码减至最少:
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do if /I "%%N" == "Path" call set "PATH=%%P" & goto GetUserPath
:GetUserPath
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKCU\Environment" /v "Path" 2^>nul') do if /I "%%N" == "Path" call set "PATH=%PATH%;%%P" & goto ProcessSetup
:ProcessSetup
要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
echo /?
for /?
goto /?
reg /?
reg query /?
rem /?
set /?
顺便说一句:
现在,一个应用程序必须添加到 Windows 注册表中的PATH 才能工作,现在的编码很差。
仅当应用程序设计为主要从命令提示符中手动执行时,才应在 Windows 注册表中向 system 或 user PATH 添加目录路径应用程序用户的窗口。在这种情况下,将应用程序的目录添加到 Windows 注册表中的 system 或 user PATH 对应用程序的用户很有帮助。
但主要通过图形用户界面使用的应用程序应将其目录路径添加到 Windows 注册表中的其他位置。常见的是将可执行文件的名称与扩展名添加到
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths
或应用程序(套件)的特定注册表项,可由应用程序(套件)的所有组件查询。
另请参阅Where is "START" searching for executables? 上的回答