Wednesday, April 14, 2010

Taming All Users Desktop and Start Menu Environment Variables in Windows 7 and XP

Some Background


This week I installed Windows 7. I enjoy many of the new features but have also come across several annoyances. I expected to have a few issues but those relating to batch scripting and the location of profile information are particularly perplexing. There may be some rationale behind moving the data but I haven't been able to find an official Microsoft explanation. At my job we manage thousands of workstations so we've got a heavily scripted deployment environment. It is extremely efficient except during transitional periods when we are between operating systems. Currently, we are testing a lab of Windows 7 machines but will still plan on supporting well over 2000 Windows XP machines for several more years. My goal is to make the transition to Windows 7 as painless and quick as possible. Before I can do that however I must get our batch scripts to be cross-OS between Windows 7 and Windows XP. I've left out Vista because we never deployed a single Vista machine (thank goodness). Enough babble, onward!

The Guts of the Problem


When writing batch scripts in Windows XP, you can access the All Users Desktop and Start Menu paths using these enironment variables:

%ALLUSERSPROFILE%\Desktop
%ALLUSERSPROFILE%\Start Menu


These really made it quite easy to...
  • script a file copy
  • pass these paths as parameters to other scripts or programs
  • or even to open to these locations in windows explorer
In Windows 7, for unknown reasons, the environment variables have been modified and the All Users Desktop and Start Menu paths have been moved to completely separate folders. So you'll need to use these variables instead:

%PUBLIC%\Desktop
%PROGRAMDATA%\Microsoft\Windows\Start Menu\


Technically you could use the Windows XP environment variables, but they don't work as expected in all situations. Here is a simple demonstration. Open an elevated command prompt and type the following 3 commands and hit enter after each line.

cd %ALLUSERSPROFILE%\Desktop
mkdir test
dir


Now, look on your Desktop. The directory "test" was successfully created. Great! That part worked. Now, head back to the command prompt for the bad news. After you typed the dir command we would expect to see a directory listing that lists the directory "test". Instead we are greeted with an empty, unhelpful directory listing that states "File Not Found". Well we just created a directory so we know this just isn't true. Something has gone horribly wrong. If you want another example of why this is a problem simply type %ALLUSERSPROFILE%\Desktop into Windows Explorer. You'll get an access denied message. Fail.

So we are in a bit of a bind here. We don't want to write a bunch of IF/ELSE statements in our scripts but since the paths returned by environment variables are flawed we really don't have any other choice. So how can we do this in as few lines as possible? Continue below for a 1 line solution that requires some editing of your Windows XP only scripts.

A Crude but Acceptable Solution


Place the following one line of code (there should not be a line break) at the top of your batch scripts then use %AUDESKTOP% or %AUSTARTMENU% to refer to the All Users Desktop and Start Menu respectively.

IF DEFINED PUBLIC (SET AUDESKTOP=%PUBLIC%\Desktop) & (SET AUSTARTMENU=%PROGRAMDATA%\Microsoft\Windows\Start Menu) ELSE (SET AUDESKTOP=%ALLUSERSPROFILE%\Desktop) & (SET AUSTARTMENU=%ALLUSERSPROFILE%\Start Menu)

Here is a little demo script that you can use to make sure the script is working correctly in your environment:

IF DEFINED PUBLIC (SET AUDESKTOP=%PUBLIC%\Desktop) & (SET AUSTARTMENU=%PROGRAMDATA%\Microsoft\Windows\Start Menu) ELSE (SET AUDESKTOP=%ALLUSERSPROFILE%\Desktop) & (SET AUSTARTMENU=%ALLUSERSPROFILE%\Start Menu)
ECHO All Users Desktop is at path: %AUDESKTOP%
ECHO All USers Startup is at path: %AUSTARTMENU%
pause


There may be other differences in environment variable names between Windows 7 and Windows XP and this script could certainly handle those if discovered. Please post them in the comments for the rest of us.

How to Actually Implement It?


Ok let's assume you have a simple batch script such as the one below that currently only works in Windows XP but that you'd like to get working in Windows 7 too. All it does is open two Windows Explorer windows (one to the all users desktop and one to the all users start menu) but is giving you two access denied errors in Windows 7:

%SystemRoot%\Explorer.exe /n, "%ALLUSERSPROFILE%\Desktop%"
%SystemRoot%\Explorer.exe /n, "%ALLUSERSPROFILE%\Start Menu"


Your modified, cross-OS script should read like this and will work properly in both Windows 7 and Windows XP:

IF DEFINED PUBLIC (SET AUDESKTOP=%PUBLIC%\Desktop) & (SET AUSTARTMENU=%PROGRAMDATA%\Microsoft\Windows\Start Menu) ELSE (SET AUDESKTOP=%ALLUSERSPROFILE%\Desktop) & (SET AUSTARTMENU=%ALLUSERSPROFILE%\Start Menu)
%SystemRoot%\Explorer.exe /n, "%AUDESKTOP%"
%SystemRoot%\Explorer.exe /n, "%AUSTARTMENU%"


Voila! You have a cross browser script. Now, I admit it is a pain to go through and Find/Replace all the instances of the old style of scripting but if you have a large enough support environment it will be worth your time since you won't have to have two versions of the same script and only has to be done this one time.

One Final Caveat


Remember, when you run batch scripts that access either of these folders you're going to need elevated (administrator) permissions. This means you need to right click on the script and choose "Run as administrator".

If anyone finds a better way to implement this or knows of a hidden environment variable that I am missing, please let me know!