User Logon Scripts            Apr 22, 2004

The design of  SFU's Active Directory does not give local OU administrators the right to modify any of an individual user's properties and so certain common administrative tasks must be performed in a non-traditional manner.

One such example is the path to a user's profile, which has been populated with variables that then get set at the local machine (as opposed to simply hard coding a path in AD).  This allows users who work in more than one department or faculty to have an environment appropriate to where they're currently working.

However, not all customization necessary for a user can be done through a profile. "Traditionally", such customization is done through group policies, but since the SFU AD architecture does not support policies applied to an individual user,  some other tack must be taken.

Logon scripts are the preferred method of doing this and a logon script can give all the personalization that a group policy can (and perhaps ever more), and do it in an easily understandable manner.

There are two types of logon scripts available in Active Directory.  The first is specific to a user, and is defined on the same property page as their profile path.  However, this field takes an absolute path - variables are not accepted - and so a logon script defined there would follow the user everywhere, perhaps defining resources not available to them in a particular location, perhaps undefining (is there such a word?) resources that should be available to them.  That alone is enough to disqualify this type of logon script, but scripts called from this location must live in the SYSVOL share of the domain controllers, an area of the machine that OU admins do not have write access to.  This latter restriction (and the administrative nightmare required to get around it) makes the user-specific logon script a non-starter.

Thankfully, there is a solution.

It is possible to specify (through a group policy) a logon script to be executed by all users who sit down at a particular machine.  This type of script is executed late in the login process, meaning that all environment variables defined within the machine are available to the script for conditional testing.  This conditional testing means that while the same script is executed by all users (at that machine), what actually gets done could be specific to each user.

For example, the script could say

    If the user is ALAN, do this, otherwise do this.

The script could go further and say

    If the user is ALAN, AND he's sitting at THIS machine, do this, otherwise, do this.

The "do this" part could be almost anything, including setting the same registry values that are not otherwise settable in Group Policy as a result of SFU's architecture.

Scripts can be old-fashioned BAT files, similar but slightly more powerful CMD files, VBS or JS files, or even an EXE.  It's beyond the scope of this document to give any programming info at all; you get to figure that out for yourself.  What I will do is to describe the procedure to create a logon script that gives everyone who sits down at a particular computer their redirected My Documents folder mapped to a drive letter.

The first thing to do is to create the script itself.  For this example, the script is a text file named MAPDRIVE.CMD, created in Notepad containing the single line

NET USE M: "\\ACS-SERVER1.ACS.SFU.CA\ACS USERS\%USERNAME%\MY DOCUMENTS"

Note the quotes around the UNC path.  Since the folder MY DOCUMENTS has a space in the name, omitting the quotes would attempt to map to a folder named MY, using the password DOCUMENTS.

Create the file, save it (ensuring that the name is not MAPDRIVE.CMD.TXT), then copy it. (Explorer - select - Edit - Copy).  We are later going to paste it to a folder on one of the domain controllers, and pasting it is going to be way easier than any other means of getting it there.

Open Active Directory Computers and Users, go to your OU, go to the OU containing the computers you want to run the above script (maybe the same OU), open Properties, go to the Group Policy tab and create a new policy.  In my case, it's called ACS Logon Script.
 

Two important points:

1. It's critical to add the OU prefix !  All Group Policy Objects (GPOs) are visible to all administrators in the organization and GPOs do not require a unique name, since GPOs live inside a (system created) unique folder.  That means that there could easily be a dozen GPOs all named Logon Script.  That's no problem, until you create another OU and wish that other OU to also run your same logon script.  Which of the dozen policies named Logon Script is your policy ?  It's a genuine pain to determine this, and so we insist on the OU prefix as part of the policy name.

2. Policies are applied to OUs and in this case, scripts are going to be run based upon the OU a computer is in.  This again points to OU membership based upon management, not upon geography, politics, or any of the other "obvious" reasons for membership (unless of course those reasons also coincide with best management).

Edit that new policy.  Go to

    User Configuration
        Windows Settings
            Scripts
                Logon
                    Properties

The Logon Properties page appears.  Click Show Files
The Logon folder appears.  Paste the file you copied earlier into this window.
Close the window.
Back at the Logon Properties page, click Add.
Click Browse.
Select the file you just copied, then click Open.

Personal rant here.

Why Microsoft still, after all these years, does not name buttons appropriately is just another sign of their corporate sloppiness.  The function call to bring this window up has a field for the names of the buttons !   The programmer that wrote this part of the code should have added the three letters A d d  to the parameters of the call !  Instead of typing those three letters, he took the lazy/sloppy way out and typed a comma (meaning use the default), and so we end up with a button labelled Open, when Open is not what we want to do.

End rant.

There are no parameters to this script, so click OK.
Click OK again.

Since this policy is in the User Configuration part of the policy, but will (likely) be applied to an OU containing machines and not users, we must enable loopback mode.  Go to

     Computer Configuration
        Administrative Templates
            System
                Group Policy

and enable

    User Group Policy loopback processing mode

For Mode, pick either Replace or Merge.  I would suggest Merge in the case of this (and in fact most) scripts.

Close the Policy Editor.

At reboot or at the next group policy refresh interval, the policy will be applied to the machines in the OU.
 

Notes:

1. As with all policies, there may be up to a 15 minute delay before the policy is applied, so don't worry if an immediate test doesn't seem to work correctly.  You've done all this work on one of the domain controllers and copied the script file to one of the controllers, but a workstation logging in may get its policies from one of the other controllers.  You need to wait for the controllers to replicate, which could take up to 15 minutes.

2. The SETX command, available from the Windows Resource Kit or downloadable here, can be an extremely useful command.  It allows you to set permanent environment variables in either the user space or the machine (system) space.  (Variables set through the SET command disappear when the CMD session exits.)  This command in a suitable scipt can be used to remove some of the drudgery of initial machine setup.

SETX in a STARTUP script, using the -M parameter, requires that the machine be rebooted to activate the variable.  I've found a convenient way to do this is to test (in the script) to see if the variable is set.  If it is, do nothing.  If it's not, set it and reboot.  Here's a sample of a STARTUP script.

if "%profileserver%" == "acs_server.ucs.sfu.ca"  goto check_share

\\acs_server.ucs.sfu.ca\sw\tools\setx profileserver acs_server.ucs.sfu.ca -m
\\acs_server.ucs.sfu.ca\sw\tools\setx profileshare depts\ss\%1\profiles -m
\\acs_server.ucs.sfu.ca\sw\tools\rm_down.exe /reboot

:check_share

if "%profileshare%" == "depts\ss\reg\profiles"  goto done

\\acs_server.ucs.sfu.ca\sw\tools\setx profileserver acs_server.ucs.sfu.ca -m
\\acs_server.ucs.sfu.ca\sw\tools\setx profileshare depts\ss\%1\profiles -m
\\acs_server.ucs.sfu.ca\sw\tools\rm_down.exe /reboot

:done
 

3. The AD naming policy that insists upon locally created accounts being prefixed with OU space presents a wee bit of a problem when that account name is used in a script.

For example, a script may contain the line

    If %username% == "ACS Installer" goto ACS_INSTALLER

However, this will fail.  The line needs to read

    If "%username%" == "ACS Installer" goto ACS_INSTALLER

Note the extra quotes around the variable.

4.  Additional information on VBS scripting can be found at Microsoft Developer's site.  Script engine 5.6 (the newest as of Mar 2003) and documentation can be downloaded from a local SFU site.

5. Patches that are not normally applied through Windows Updates can also be applied via a STARTUP script.  For example

rem check to see if we've already applied this patch

if exist %windir%\inf\q831167.inf goto end

rem guess not, so apply the patch

\\acs_server.ucs.sfu.ca\sw\microsoft\patches\q831167\q831167.exe /q

:end