Why can't Windows handle an environment variable in Path?

45

16

My colleague and I have identical Dell workstations with Windows XP Professional x64 edition installed.

My Path environment variable starts with:

%JAVA_HOME%\bin;...

My colleague's Path variable includes the same directory, specified using the same environment variable, but it is not the first item in his Path.

If I access system properties -> environment variables and change the value of my JAVA_HOME variable, the version of java found from the command-line changes as I expect. This is starting a brand new console window, to be sure to pick up the changes.

But on my colleague's machine, it does not. He continues to find his previous version of Java until he brings up his Path variable and saves it (even if he makes no changes to it). (Again, this is when starting a brand new console window.)

I have been observing this inconsistency on Windows for about 6 months now and very curious about it. We have way too many versions of Windows in our office, so rarely have I had a chance to see this happening on two machines running the exact same OS version, until now.

What is causing this? Why does his machine not re-evaluate Path, using the new JAVA_HOME, when mine does?

(Is it because it's not the first thing in the Path? If so, how could that be, and why? I'd do more tests to check, but I think he's now fed up with it and would like to get back to work.)

skiphoppy

Posted 2009-08-21T18:12:45.617

Reputation: 2 193

I'm looking at this in Windows 10 -- variable substitution into PATH failed intermittently to work. Going to Environment Variables & saving (without change) and then opening a new CMD prompt solved the problem. – Thomas W – 2016-10-12T02:03:16.200

9For all you guys voting to close (3 at the moment) ... if there's a dup somewhere, a comment pointing me to it sure would be nice.

If it's not a dupe ... then telling me what you think is wrong with this question would also be nice. – skiphoppy – 2009-08-21T18:40:21.550

1Perhaps because it is more a system question than a programming one, although it has a direct impact on programming, that's why I don't vote to close it... :) – None – 2009-08-21T18:49:43.297

9Attenion close-nazis: I'd like to promote the view that if a question was appropriate on Stack Overflow before superuser.com and serverfault.com arrived, then it is still appropriate today. This is a programming question. – skiphoppy – 2009-08-21T19:12:58.023

Do you mean that programmers are only users of Windows, who may have this problem? Shut up you, programmer-nazi! Secondly, before more appropriate Q&A site arrived, you had no option to post question here. The hospitality of SO must be not an argument for abusing it. – Val – 2013-07-07T15:54:05.717

Answers

37

Your path is the concatenation of the system path followed by the user path. Additionally, system environment variables may not contain references to user environment variables, and any such references will not be expanded. To get the desired result, insert the reference to %JAVA_HOME% in the user environment variable PATH, or create such a variable if it doesn't already exist.

Perhaps a simplified example will make this clearer. Suppose the SYSTEM environment is

ProgramFiles = C:\Program Files
SystemRoot = C:\WINDOWS
PATH = %SystemRoot%\SYSTEM32

and the User JSmith's environment is

JAVA_HOME = %ProgramFiles%\Java\bin
USERPROFILE = C:\USERS\JSmith
PATH = %JAVA_HOME%\bin;%USERPROFILE%\bin

then the resulting path would be

C:\WINDOWS\SYSTEM32;C:\Program Files\Java\bin;C:\Users\JSmith\bin

as desired.

JPaget

Posted 2009-08-21T18:12:45.617

Reputation: 475

3My system had some user env variables with the same name as some system env variables. Echoing PATH wouldn't expand them - after reading this, I removed the duplicate user variables as I wondered if they were picked up with precedence (but unable to be expanded). This has now worked for me - many thanks. :) – Michael – 2014-11-07T09:53:27.433

Is there a way via Powershell to get the original unexpanded PATH? I was hoping to append to my PATH while preserving the unexpanded environment variables in it. – CMCDragonkai – 2016-12-23T14:22:50.303

Solved it with some help from another question. Write a powershell script to handle this: https://gist.github.com/CMCDragonkai/a02d77c2d7c0799dd42fd2aab26a3cd5

– CMCDragonkai – 2016-12-23T15:46:32.330

17

Check in the Windows registry under this key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\Environment

IF the environment variable needs to be expanded (here: %JAVA_HOME%)

then the variable must be set as a REG_EXPAND_SZ value.

If using reg.exe via command-line to add/edit registry values, it defaults to type REG_SZ. Specify the type REG_EXPAND_SZ by using the reg add /t REG_EXPAND_SZ option.

climenole

Posted 2009-08-21T18:12:45.617

Reputation: 3 180

yep ... this is one of those settings that I always seem to forget ... pesky registry ;-) – Eddie B – 2013-09-06T05:20:33.127

9

There is a definite problem with expanding environment variables within the PATH variable when the variable expands to a path that contains spaces.

We created our own system level variables like "OUR_ROOT=c:\MyRoot" and then used it in system PATH like "PATH=;%OUR_ROOT%\bin;" and that gets expanded correctly to "PATH=;c:\MyRoot\bin;". So far no problem.

But, on Windows 7 (32-bit), I had a product install itself and create system environment variables like this:

STUDIO_BIN=C:\program files\Company Name\Product Name 10.4\bin

and it added it to the system PATH variable:

PATH=<other path elements>;%STUDIO_BIN%;<more path elements>

But the PATH values shown in CMD contained "%STUDIO_BIN%;" and not the expanded path. The value in My Computer > Properties > Advanced > Env.Vars remained unexpanded as well. This meant I couldn't run programs that required a DLL in that directory.

By just changing STUDIO_BIN (via My Computer>Properties>Advanced ...>Env Vars) to a name without embedded spaces :

STUDIO_BIN=C:\ProductName\bin

and then restarting the CMD window, the PATH is now:

PATH=<other path elements>;C:\ProductName\bin;<more path elements>

Another solution is to sufficiently edit the system variable you are using in the PATH using the My Computer > Properties > Advanced... > Environment Variables dialog. I tried adding a character and removing it to make a 'change' and then OK'd out, started a new CMD prompt and PATH was NOT correctly expanded. I then tried deleting part of the path so it was

STUDIO_BIN=C:\Program Files\Company Name

(omitting "Product Name 10.4") and lo, and behold, the next CMD prompt showed PATH with STUDIO_BIN properly expanded!

Strangely enough, if I went back in and added the "Product Name 10.4" to STUDIO_BIN (including all the spaces that were originally there before I started mucking with it) and PATH was STILL correctly expanded.

Evidently with enough change to its contents, the PATH variable undergoes some extra processing in the Environment Variables dialog that allows it to work. Processing that's not done when the variable was added by the product's installer (which probably just modified PATH in the registry directly).

I'm almost positive this was a problem with XP as well. It just resurfaced for me in Windows 7 as I was putting together a new development machine. Apparently it has not been fixed by Microsoft.

Apparently even MS defined variables like %ProgramFiles% won't expand correctly in the PATH.

This page provides a possible answer if you're setting PATH via the command-line or batch file. (Enclose the whole command after SET in quotation marks.) I don't know what installer the product I installed used to set the environment variables, but it evidently went around whatever processing is needed to properly expand the paths with spaces.

So - to summarize, you can either:

  • change the paths (and move all associated files) to paths without spaces, or

  • edit the variables that are failing to expand in the Environment Variables dialog (changing them enough to get them to process correctly - I'm not positive how much is enough).

RobDavenport

Posted 2009-08-21T18:12:45.617

Reputation: 191

5

there are two levels of environment variables, global and user. If he has %Java_home% set as a user environment variable but is instead changing the global one, he won't see any difference.

Sekhat

Posted 2009-08-21T18:12:45.617

Reputation: 181

2

You have to consider the order in which variables are set upon login. If you try to use a variable before it is set, it will come out as the empty string.

The effective PATH is the concatenation of the user's PATH variable followed by the global PATH variable.

User variables are set before global variables, so you can't use global variables in you user PATH variable. Additionally, variables are set in alphabetical order, so you can't use variables that sort before PATH.

(This applies to Windows 7 at least. I haven't tested this on newer versions.)

cbarrick

Posted 2009-08-21T18:12:45.617

Reputation: 131

2

Make sure there are no spaces in the PATH when you are defining your own user environment variables. eg: C:\GNAT\bin; C:\GNAT\include wont work, because of the space between the ";" and "C:\GNAT\include".

Nij

Posted 2009-08-21T18:12:45.617

Reputation: 21

2

Add the environment variables whilst logged onto the /console session using MSTSC.

Reboot the machine and you will find your environment variables will have persisted.

There appears to be a quirk in the O/S depending on how you were connected to the machine when you attempted to change the environment variable.

Justin

Posted 2009-08-21T18:12:45.617

Reputation: 21

1

I've had the same problem, and I know how to fix it, its lame.

Just edit your PATH again, but make no change, and re-save PATH. For some reason this causes all nested environment variable references to get re-evaluated.

If it doesn't work do it a few more times, somehow it just works itself out.

BAP

Posted 2009-08-21T18:12:45.617

Reputation: 11

1

It might be related to the "delayed environment variable expansion" feature (or lack thereof), or perhaps you can take advantage of this feature to always have a correct solution.

from a cmd prompt

set /? 

and read the section describing "delayed environment variable expansion", which includes a small example to test

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

If you don't get the echo line, then that might explain it...

If, however, you start your cmd.exe with /V option, then you can use "!" instead of "%", which changes the behaivior

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

For me (running on XP), the 1st script did not work, but the second version did (with cmd.exe /V)

libjack

Posted 2009-08-21T18:12:45.617

Reputation: 111

1

I do believe what Windows fails to expand a variable in PATH because it thinks what it not defined yet. Consider:

REM Ensure variable is undefined
SET UNDEFINED=
REM And then try to expand it
ECHO UNDEFINED=%UNDEFINED%

This hypothesis conforms with my other observation - adding %ProgramFiles%\Something to the users PATH will always result in expected expansion of %ProgramFiles%, given it has been defined in machine environment at the time of variable change notification (due loading order - MACHINE and then USER). But when you modify machine environment correct variable expansion only happens at the boot time (right now I have no idea how and why this not happens on the regular basis).

user539484

Posted 2009-08-21T18:12:45.617

Reputation: 450

0

Perhaps you are doing it wrong?

I tried with Windows XP Pro SP3 (32bit). I do have a path with several occurrences of %JAVA_HOME% (and %JAVAFX_HOME%, etc.). I go to command line, type PATH, I see the variables expanded. Good.

I change the value of JAVA_HOME. Back to the same command line window, PATH again, same value... as expected (by experience!).

I open a new command line window, type PATH, gotcha, I see the new value.

Not sure what is the exact mechanism there, but it seems that any running program, including cmd.exe, capture the values of environment variables at starting time, and doesn't look back... (although I believe a good behaved program can listen for env changes, not too sure though).

It might be seen as a feature or a bug or annoyance, but that's the way it works. Hey, at least, unlike Win9X times, we don't have to reboot the computer! And unlike NT times (IIRC), you don't have to log out and back.

Why the inconsistency? The ways of Microsoft are inscrutable... :-P

PhiLho

Posted 2009-08-21T18:12:45.617

Reputation: 271

This isn't it. After the change we're testing in a fresh command window. We're aware of the fact that changing the system values doesn't change the values for running processes. – skiphoppy – 2009-08-21T19:11:13.783

OK, hence the 'perhaps'... :-) And my explanation doesn't cover the inconsistency, but might be useful to some newbie... :-P I mostly wanted to point out that variable expansion works everywhere in the path... for some systems! (all those I used... always 32bit). – None – 2009-08-22T08:38:19.780

0

I have resolved setting the environment variables in System > Advanced Settings > Environment Variables.

There's two panels, User and Global variables (user is your Windows username) and System Variables are Global variables, so if you set 'New' from User variables, such as JAVA_HOME and put your path below, you will set variables even if your global path have program files inside folder.

thunder_nemesis

Posted 2009-08-21T18:12:45.617

Reputation: 1