I have a habit of using the command line FTP program that comes with Windows. It's not the greatest, but it's convenient. I went to use it one day, and ran into a situation I had not seen before:

C:\Users\Evan>ftp 'ftp' is not recognized as an internal or external command, operable program or batch file.

(I closed the console and can't recreate it easily, so I'm emulating the console bits.) This struck me as very odd, especially give that I had just used the program the day before. What happens if I specify the full path?

C:\Users\Evan>c:\windows\system32\ftp ftp>

It works.

Okay, so now I think I'm getting somewhere. I installed a new program in the morning, called Aqsis (it's a rendering engine), and it had asked if it should add itself to the PATH environment variable. I said sure, so I knew it had messed with it. So I thought, "okay, let's look at PATH and see if System32 is still present," figuring that Aqsis had killed my environment variables. So:

C:\Users\Evan>echo %path% g:\Program Files\Aqsis\bin; g:\Programs\MiKTeX\2.7beta4\miktex\bin; %SystemRoot%\system32; %SystemRoot%; %SystemRoot%\System32\Wbem; G:\Program Files\QuickTime\QTSystem\; G:\Program Files\TortoiseSVN\bin; G:\PROGRA~1\SECURE~1\SecureFX; g:\programs\cygwin\bin; G:\programs\lame3.97; g:\Programs\Python25\

(I've split it up so you can see the directories; I haven't seen a shell that is nice enough to give you output that is actually readable without further work.)

Well, that's odd; my System32 is the third entry in my PATH, so it's there. (I will point out that for someone who knows Windows really well, there is already an indication that there is something wrong here. I'm not good enough to have spotted it.) Well... maybe the SYSTEMROOT variable is screwy? Checked that, and everything is good:

C:\Users\Evan>echo %systemroot% C:\Windows

By this time I'm already talking to my friend Tim (who happens to work on the Windows shell team), and he doesn't have any insight as to what is going on. However, he suggests trying the Sysinternals tool Process Monitor to see what is going on. (This is the same sort of tool that Linux's strace is.) So I started that up, told it to filter events so only those from CMD.EXE would pass through, went back to the console, and typed "where ftp." (If I were consistent I would show a screenshot of trying to run FTP, but I'm not.) The relevant results (and many more) are shown below: [Results from Process Monitor]

The first thing to note is what it does for most things in the path. (The top three lines which are highlighted.) It issues three operations in sequence: CreateFile, QueryDirectory, and CloseFile. Basically it checks each directory to see if there is a file in it that matches the pattern where.*. Each time it fails to find anything (you can see the NO SUCH FILE return from the QueryDirectory calls), so just closes the directory handle.

But an amusing thing happens when it gets to the third entry of the path. Instead of trying to open the directory %SystemRoot%\System32 or C:\Windows\System32, it is trying to open the directory C:\Users\Evan\%SystemRoot%\Sysetm32, which plainly doesn't exist.

Meanwhile Tim is doing some investigation of his own, and discovers something else interesting. First, when he enters echo %path% in the command line, none of the entries contain %SystemRoot%. However, the raw version of the PATH variable, as it is found in the registry and in the environment variables dialog accessible through the control panel, does contain references to %SystemRoot%.

Now we're getting somewhere. It's clear that the shell is seeing an unexpanded versions of the PATH variable. In other words, it sees the literal string "%SystemRoot%" where it should see the expanded form, "C:\Windows". Now we just have to figure out why. Tim is thinking there may be some sort of order dependence, and maybe PATH is being defined before SYSTEMROOT. I'm a bit skeptical but have no better theory to work on, so I start snooping around in regedit.

I find the location in regedit where PATH is defined: [Regedit] But I don't see anything out of place, and what I do see matches up with what Tim sees on his computer.

Finally Tim gets the epiphany. Look at the type of the PATH value on my computer; it is REG_SZ. This is a literal string, which doesn't get expanded when read. (SZ = a string terminated with a zero.) The type of PATH should be REG_EXPAND_SZ, which tells Windows to do replacement of environment variables within the string it returns.

Simply making the change in regedit (you have to delete the existing key and create a new one; you can't simply change the type) isn't enough because changes to the ControlSet keys in HKLM don't take effect immediately, so I go into the environment variables dialog from within the control panel, make a noop change to PATH from there, and then OK my changes. Windows happily replaced the PATH value that was there with a REG_EXPAND_SZ version of the same, and everything is happy.

So the final diagnosis is the Aqsis installer incorrectly created the PATH variable with type REG_SZ instead of REG_EXPAND_SZ.