1
votes

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:

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

SET
Pause

The SET command lists the environment variables.

I call this script from PowerShell like:

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

I did also try to call it like:

& C:\...\Batch.cmd

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

Output-Comparison

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?

Update #1:

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

Some more details:

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.

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.

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")

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.

Update #2:

New Environment

1
Can you reproduce issue after reboot?user4003407
What about something like this?BenH
@PetSerAl: I did just try it. I can confirm, that it is OK after a reboot.Walhalla
@BenH: That sounds suitable. I think I will have to test this with a clean install ...Walhalla
To ease comparing I suggest you issue in Powershell (gci env:path).value.split(";") and in a cmd window cmd /D /K @for %A in ("%Path:;=";"%") do @Echo:%~A the latter will exclude possible autoruns which might inject the additional path entries.user6811411

1 Answers

1
votes

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

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

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"

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

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 /?

The result is the error message:

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

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

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 /?

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 /?

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.

So there are 3 command processes now running with

  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.

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.

Close now all 3 command process windows not further needed.

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.

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.

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

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 /?

By the way:

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

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.

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).

See also answer on Where is "START" searching for executables?