Monday, February 4, 2008

Logon Scripts: A Token Effort

How many of you have been struggling to make your logon scripts work when Vista's UAC is enabled? (I'm holding my hand up here.) Let me share my effort with you so you can avoid the same problems.

Basically all of the difficulty stems from the way UAC isolates processes. Logon scripts are processed by a process :-) - it's important to know what integrity level the process operates with and what token the end user is using. (If this last sentence made no sense to you, you better read my article Let's Talk UAC for the Enterprise before continuing.)

I'm sure many of you have read or been told that launching scripts by Group Policy Objects (GPO) is the way of the future. Indeed, I too was launching my scripts via GPO, but it is this very thinking that got me into trouble.

Logon scripts launched via GPO are processed using the user's "highestAvailable" token. This causes resources such as drive mappings to be associated with that Full Token. The other thing to remember is that the user's session and desktop are then presented using the Standard Token. There's no problem for basic users because they only get one token - their Full Token and Standard Token are one and the same.

But UAC starts causing troubles for all the other users who have split tokens (Administrators, Power Users, etc.) - anyone with two tokens. The GPO maps drives as a resource of the higher token and the user is left to operate in Windows with their lower token. UAC prevents the lower token from seeing the resources of the higher token. Therefore the users don't get the mappings you've assigned them.

It's unfortunate that Vista isn't smart enough to process scripts and assign resources against all the user tokens it creates during the logon process. But Microsoft is aware of the problem and has tried to offer a few solutions (none of which work 100%). The first and most common solution offered comes from their guide, Deploying Group Policy Using Windows Vista
- the Group Policy Scripts can fail due to User Account Control section describes the problem (but not entirely accurately). It goes on to offer a solution that I will call the LaunchApp solution.

The LaunchApp Solution

The LaunchApp solution suggested by Microsoft is a horribly kludgy affair that doesn't work 100%. Basically, Microsoft is providing a LaunchApp script that is capable of creating a scheduled task that launches another script. Microsoft just expects your logon script GPO to call the LaunchApp script instead - that will then schedule an immediate task to run the script you originally wanted to use to map drives. (confused yet) The idea is that the scheduled task will trigger your script to run once the desktop is created, which will cause it to run using the user's Standard Token rather than the user's Full Token. The users will then be able to see the mappings because they are operating with the same token that has been assigned the mappings.

Some small problems...
1) The scheduled task fires off when the Desktop session is created. The other thing that fires off at that moment is anything in the user's Startup folder. One nice example is Microsoft's own Outlook product. Users typically put that in the Startup folder so that they always see their e-mails. It will often be configured to store things like a Personal Address Book on a mapped network drive - guess what hasn't been mapped yet when Outlook goes looking for a PAB file? The results aren't so good.

2) The LaunchApp acrobatics gets the mappings to associate with the Standard Token but still does nothing for the user's elevated token. When a user elevates a program, all mappings are unavailable to the elevated program. Quite an inconvenience to say the least.

The Merged Mapping Solution

Microsoft's latest suggestion for solving the mapping problem is described in KB937624. I call this the Merged Mapping solution - it is by far a better solution, but it also has its problems. Basically, Vista has a wonderful little registry key that tells it to merge the drive mappings between all of a user's tokens: HKLM \Software \Microsoft \Windows \CurrentVersion \Policies \System \EnableLinkedConnections = 1. What could be simpler right? Create this key on every workstation and it will tell the OS that the mappings associated with one token are to be mirrored into the other token as well.

I'm not sure if Vista understood that key right out of the box or whether it was added later as part of a hotfix. All I know is that I was made aware of it rather late in the game. I did use this solution for a while before discovering the problem it has...

When I first implemented it, it worked great. Mappings created against one token were made available against the other token - no matter whether the user was an Administrator or a Power User (remember Full Administrator Token vs. Full Token). Well, the installation of Service Pack 1 (SP1 RC1) changed all that - Vista stopped merging mappings between the Standard Token and a Full (non-admin) Token. It now only merges mappings between the Standard Token and a Full Administrator Token. -- Not so good when all of my users are Power Users -- completely useless in fact.

I've opened a Premier Support call on this problem. It's been over a month and they are still trying to decide if it is really a problem or if there is an easy solution. You see, if you read the KB article mentioned above, you may notice that it only mentions it as being a fix for Administrators and doesn't mention other cases at all (but I know it used to work!) -- I of course thought that the discussion of only Administrator wasn't a specific limitation but rather Microsoft's usual over-simplification of the discussion. I'll update this post when I know more.

The AD Profile Solution

Ultimately, I found the best results for mapping drives were achieved by avoiding the logon script GPO entirely. Instead, I fell back on a tried and true method that has been around for a decade or so - I now launch my logon scripts via user profile in Active Directory.

Not only is this method extremely simple, but it is extremely effective. Logon scripts launched in this way are processed with the user's Standard Token - the same one the user is using when they are first presented with their desktop. It doesn't matter if the user is a Basic User, Power User or Administrator - the user will be able to see the mappings assigned to them because they are associated with the correct token. Stop wasting your time with a GPO script - it's not worth the effort.

Despite the script being processed by a Standard Token, it is still processed before the desktop is made available to the user. This ensures that all drive mappings are created before any application in the user's Startup Folder are processed - all applications in the Startup Folder should launch successfully as a result.

If you choose to adopt this new old approach, I still recommend you implement the merged mapping solution described in KB937624. In your environment it might merge the mapping with all types of user tokens, or it might just merge them for administrators - either way it will still be an improvement. Keep in mind though that this solution cannot do anything to merge mappings between two different user accounts. So it cannot help enterprises that make an administrator use a standard user account for routine tasks and then a separate administrative account for admin tasks. (I will be looking for solutions to this in future articles.)


Aaron said...

What's the benefit of adding your users to the Power Users group?

Gordon Martin said...

Hi Aaron,

Actually, the disadvantages tend to outweigh the benefits. But without giving too much away, you might want to check out this list of apps that need additional rights in order to function:

But being a member of Power Users does cause a user to have two tokens, which can lead to a few more elevation prompts.

Gordon Martin said...

BTW, here's a fun example of how using Power Users can be a disadvantage.

FancyCat said...

Neat blog!!!!!!

B. Good said...

Finally got the MS Kludge(TM) working to create a scheduled task to run my logon script. BUT, I still cannot "regedit /s" to tweak things in the user's registry because of UAC. Any ways to work around THAT?? (Short of ditching UAC)

Anonymous said...

Very cool overview. I'm surprised this isn't closer to the top of the Google results, because this is the only place that really summarizes all the options.

Anyway, I just wanted to make a quick comment - it is possible to eliminate both problems with launchapp.wsf.

#1: Add a "WScript.Sleep" statement at the bottom of launchapp.wsf. The scheduled task doesn't wait for the desktop session to start. It's just that normally launchapp.wsf terminates before the scheduled task gets a chance to start. (And of course you'll also need to enable "Run logon scripts synchronously.")

#2: Run the script twice - once for the elevated token, and once for the restricted token.

There are more elegant solutions too, but that's the general idea.

Gordon Martin said...

Thanks for the update. People used to be able to find this as quite a high search result, but the article has naturally slid down since it is now almost 2 years old.