从PowerShell调用批处理时缺少环境变量(PATH)? [英] Missing environment variable (PATH) when calling batch from PowerShell?

查看:188
本文介绍了从PowerShell调用批处理时缺少环境变量(PATH)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在对无人参与的特殊软件安装进行故障排除.我将问题缩小到缺少的环境变量中,现在我很困惑,因为我不知道为什么会丢失它.

I am currently troubleshooting an unattended installation of a special software. I narrowed down the problem onto a missing environment variable and I am very confused now because I don't know why it is missing.

我可以重现这样的问题:

I can reproduce the issue like this:

我有一个名为batch.cmd的批处理文件.该文件包含以下代码:

I have a batch file called batch.cmd. This file contains the following code:

SET
Pause

SET命令列出了环境变量.

The SET command lists the environment variables.

我从PowerShell调用此脚本,例如:

I call this script from PowerShell like:

$Status = Start-Process -FilePath "C:\...\Batch.cmd" -PassThru -Wait

我也尝试这样称呼它:

& C:\...\Batch.cmd

与直接运行批处理脚本相比,我在 PATH 变量中缺少2个文件夹路径.看一下屏幕截图:

As result I am missing 2 folder paths in PATH variable compared to running the batch script directly. Have a look at the screenshot:

如您所见,如果直接调用脚本, PATH 变量将包含更多条目.

As you see the PATH variable contains more entries if calling the script directly.

条目本身不是我设置的.它们必须由安装程序在较早的安装步骤中创建.

The entries itself are not being set by me. They must be created by an installer in an earlier installation step.

我在设置环境变量方面经验不足,也不知道为什么会这样.

I don't have a lot experience with setting environment variables and I don't know what and why it is like this.

有人知道发生了什么事吗?

Does anybody know what's going on?

更新#1:

我仍然没有一个干净的解决方案.

I still don't have a clean solution on this.

更多详细信息:

我正在创建软件的无人值守安装.第一步称为设置.似乎该设置例程将2个文件夹路径添加到 PATH 环境变量.

I am creating an unattended installation of a software. The first step calls a setup. It seems that the setup routine adds 2 folder paths to PATH environment variable.

第二步,我调用一个批处理脚本,该脚本需要在 PATH 变量中使用这两个文件夹路径,但是由于它们不存在而失败.

In the second step I call a batch script which needs those 2 folders paths in PATH variable, but it fails because they are not there.

在尝试使用以下行调用批处理之前,我尝试在PowerShell中重新加载变量:

I tried to reload the variables in PowerShell before calling the batch with the line:

$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")

这似乎适用于PS环境,但批次没有任何变化. 第二次调用该脚本即可.重新启动后它也可以工作.

It seems to work for the PS environment but there is no change for the batch. Calling the script a second time it works. It is also working after a reboot.

更新#2:

推荐答案

每个进程都有自己的环境变量列表.每次创建进程时,Windows都会将新进程的运行进程的环境变量的当前列表复制到.

Each process has its own list of environment variables. Every time a process is created, Windows copies the current list of environment variables of the running process for the new process into a separate memory area.

子进程不能修改其父进程的环境变量,父进程也不能修改其子进程之一的环境变量.如果那是可能的话,那就意味着任何进程都可以操纵任何其他进程的工作记忆,那肯定是不好的.

No child process can modify the environment variables of its parent process nor can a parent process modify the environment variables of one of its child processes. If that would be possible it would mean that any process could manipulate the working memory of any other process and that would be definitely not good.

在命令提示符窗口中执行以下操作可以很容易地看到环境变量管理:

The environment variables management can be easily seen on doing following from within a command prompt window:

title First CMD
set PATH

第一行将命令处理窗口的窗口标题更改为First CMD.

The first line changes the window title for the command process window to First CMD.

第二个命令列出了所有以PATH开头的环境变量及其值.这通常意味着环境变量PATHPATHEXT及其值与当前在运行命令进程的环境变量列表中的值相同.

The second command lists all environment variables starting with PATH and their values. This means usually the environment variables PATH and PATHEXT with their values as currently in environment variables list of running command process.

set "PATH=%PATH%;%USERPROFILE%\Desktop"
start "Second CMD"

第一行将您的桌面目录追加到当前命令过程的PATH中.第二行再打开一个命令提示符窗口 窗口标题为Second CMD.第二个命令过程获取当前命令过程的所有环境变量的副本.

The first line appends your desktop directory to PATH of current command process. The second line opens one more command prompt window with window title Second CMD. This second command process gets a copy of all environment variables of current command process.

命令提示符窗口中运行:

Run in second command prompt window:

set PATH

输出为PATHEXTPATH,该文件末尾包含您的桌面目录.因此,在这里已经可以看到,新命令进程是使用与在启动第二个命令进程时为第一个命令进程定义的环境变量相同的环境变量创建的,而不是存储在Windows注册表中并在查看高级系统设置中的环境变量时显示的变量Windows.

Output is PATHEXT and PATH which contains at end your desktop directory. So it can be seen here already that the new command process was created with same environment variables as defined for first command process on starting the second command process and not what is stored in Windows registry and displayed on looking on environment variables in advanced system settings of Windows.

切换到第一个命令提示符窗口并执行:

Switch to first command prompt window and execute:

set PATH=
sort /?

结果是错误消息:

sort无法识别为内部或外部命令,
可操作的程序或批处理文件.

sort is not recognized as an internal or external command,
operable program or batch file.

Windows命令解释器在此命令过程中不再找到目录%SystemRoot%\System32中的

sort.exe,因为不再存在用于搜索可执行文件和脚本的所有目录路径的 local PATH 在此命令过程中,但当前目录偶然是%SystemRoot%\System32.

sort.exe in directory %SystemRoot%\System32 is not found anymore by Windows command interpreter in this command process because local PATH with all the directory paths to search for executables and scripts does not exist anymore in this command process except the current directory is by chance %SystemRoot%\System32.

第一个命令提示符窗口中运行:

Run in first command prompt window:

start "Third CMD"

在打开的第三命令提示符窗口中运行:

Run in opened third command prompt window:

set PATH

列出的只有PATHEXT及其值. PATH在第一个命令提示符窗口中不再定义,因此在第三个命令提示符窗口中也不存在.

Listed is only PATHEXT with its value. PATH was not defined anymore in first command prompt window and therefore does also not exist in third command prompt window.

第三命令提示符窗口中运行:

Run in third command prompt window:

set PATH=%SystemRoot%\System32
sort /?

显示外部命令 SORT 的帮助,因为Windows命令解释器可以在第三命令过程中找到可执行文件,因为 local PATH再次用包含sort.exe的目录的路径.

The help of external command SORT is displayed as the executable could be found by Windows command interpreter in third command process because of local PATH being defined again with the path of the directory containing sort.exe.

切换到第二命令提示符窗口并运行:

Switch to second command prompt window and run:

sort /?

外部命令 SORT 的帮助也显示在第二个命令提示符窗口中,因为 local PATH仍具有启动时的所有目录路径,包括桌面文件夹最后.

The help of external command SORT is displayed also in second command prompt window because local PATH still has all the directory paths as on starting it including your desktop folder at end.

切换到第一个命令提示符窗口并运行:

Switch to first command prompt window and run:

sort /?

仍然存在显示的错误消息,如在先前删除它后仍未定义在第一个命令提示符窗口中.

There is still the error message displayed as in first command prompt window PATH is still not defined after deleting it before.

因此现在有3个命令进程与运行

So there are 3 command processes now running with

  1. 根本没有定义PATH
  2. PATH,其其他桌面文件夹未存储在Windows注册表中,
  3. PATH,很可能只有C:\Windows\System32作为唯一的文件夹路径.
  1. no PATH defined at all,
  2. PATH with additional desktop folder not stored in Windows registry,
  3. PATH with most likely only C:\Windows\System32 as only folder path.

您现在还可以在Windows高级系统设置的用户系统环境变量列表中的PATH进行修改,但这不会更改3 上的任何内容.已运行的3个命令进程中的本地 PATH.

You could modify now also PATH in user or system environment variables list in Windows advanced system settings, but that does not change anything on the 3 local PATH of the 3 already running command processes.

现在关闭不再需要的所有3个命令处理窗口.

Close now all 3 command process windows not further needed.

上查看答案,是什么原因导致排序"未被识别为内部或外部命令,可操作程序或批处理文件?它说明系统用户 PATH在Windows注册表中的存储位置.

Take a look on answer on What is the reason for 'sort' is not recognized as an internal or external command, operable program or batch file? It explains where system and user PATH is stored in Windows registry.

我假设首先运行的setup.exe将目录路径直接添加到Windows注册表中的系统用户 PATH,它们仅对从Windows桌面启动的新进程有效或开始"菜单,但不适用于任何已在运行的进程.

I assume that setup.exe running first adds directory paths directly to system or user PATH in Windows registry which become effective only for new processes started from Windows desktop or start menu, but not for any already running process.

因此,您必须在批处理文件中执行在PowerShell脚本中已完成的操作,直接从Windows注册表中查询两个PATH的值,并为命令过程设置 local PATH当前正在执行批处理文件.

So you have to do in the batch file what you have done already in PowerShell script, query the values of both PATH directly from Windows registry and set local PATH for the command process executing currently the batch file.

@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%"

如果在目录路径列表中包含;;或目录路径列表以;结尾,则对于Windows命令解释器来说,后两个命令并不是真正必需的.

The last two commands would not be really necessary as it would be no problem for Windows command interpreter if there are ;; within directory paths list or the directory paths list ends with ;.

上述批处理代码降至最低:

The above batch code reduced to minimum:

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

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • echo /?
  • for /?
  • goto /?
  • reg /?
  • reg query /?
  • rem /?
  • set /?
  • echo /?
  • for /?
  • goto /?
  • reg /?
  • reg query /?
  • rem /?
  • set /?

顺便说一句:

如今在Windows注册表中必须将目录路径 添加到PATH的应用程序才能完全正常工作.

An application of which directory path must be added to PATH in Windows registry to work at all is poorly coded nowadays.

仅当应用程序被设计为主要在命令提示符下手动执行时,才应在Windows注册表中为系统用户 PATH添加目录路径.应用程序的用户打开的窗口.在这种情况下,将应用程序的目录添加到Windows注册表中的系统用户 PATH对应用程序的用户很有帮助.

Adding a directory path to system or user PATH in Windows registry should be done only if the application is designed for being mainly executed manually from within a command prompt window by the users of the application. In this case adding the directory of the application to system or user PATH in Windows registry is helpful for the users of the application.

但是主要通过图形用户界面使用的应用程序应将其目录路径添加到Windows注册表中的其他位置.常见的做法是将扩展名为exe的可执行文件添加到

But an application mainly used via graphic user interface should add its directory path to other locations in Windows registry. Common is the adding the name of the executable with extension to

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths

或特定于应用程序(套件)的注册表项,可以由应用程序(套件)的所有组件查询.

or an application (suite) specific registry key which can be queried by all components of the application (suite).

另请参阅在哪里开始"搜索可执行文件的答案?

这篇关于从PowerShell调用批处理时缺少环境变量(PATH)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆