Adjusting different applications to a terminal server often requires the use of scripts or command files. Scripts and command files offer a suitable scripting language syntax to perform repeat administrative tasks by sequencing default commands. Basically, applications can be adjusted during two procedures: application installation and user logon.
The changes performed directly after an application is installed on a terminal server often cover known problems. Specifically adapted scripts result in automated system environment adjustment to improve the execution of the application. Therefore, scripts comprise different actions, most of which are documented in relevant articles (for example, in the Microsoft Knowledge Base):
Changing paths that lead to wrong directories
Moving executable programs and DLLs to system-global areas
Adjusting compatibility flags
The second option for starting scripts correctly is to invoke them during user logon. On a terminal server, it is possible to assign each user a standard logon script and a terminal server logon script. Furthermore, each terminal server holds a systemwide logon script (UsrLogon.cmd). This script can perform global configuration changes that might be required on a multiple-user system. Due to the dependencies of the installed applications regarding the changes, the systemwide logon script invokes application-specific scripts for the changes.
Both solutions are based on compatibility scripts, which will be described in detail in the following section.
Compatibility scripts used to be a frequently used way to adjust older applications for their use on terminal servers. The newer applications no longer require this method and make use of more modern concepts. Nevertheless, it is worth checking out compatibility scripts, especially when the user environment needs to be optimized for stubborn applications that were never designed to run on terminal servers.
Many user session modifications with the purpose of improving applications can be performed by using special scripts. Each terminal server has several installation scripts located in the %SystemRoot%\Application Compatibility Scripts\Install directory. It might be necessary to adjust some of these scripts manually before they are executed—for instance, modifications related to default paths that are selected during application installation.
The compatibility scripts delivered for the installation of applications are just examples. They will still need to be adjusted for many environments.
A compatibility script’s logical sequence requires many interdependent script modules. The reason for this is the missing ability of individual command-line scripts to appropriately handle dynamic data, conditional branches, and user input.
When an installation script is executed on a terminal server for the first time, the script asks the administrator to enter a default letter for the home directory of each user. A file called RootDrv2.cmd is generated in the %SystemRoot%\Application Compatibility Scripts directory. This file handles the allocation of drive letters and home directories. ChkRoot.cmd is the script responsible for this initial behavior. It is also located in the %SystemRoot%\Application Compatibility Scripts directory.
The ChkRoot.cmd script works according to the following logic:
Using the RootDrv.cmd script to verify whether the %RootDrive% environment variable has already been set. If yes, it jumps to a label at the end of ChkRoot.cmd. If not, the script continues to execute.
Generating the RootDrv2.cmd script in the %SystemRoot%\Application Compatibility Scripts directory. The script is called up in Notepad to assign the user’s home directory to a fixed drive letter.
Invoking RootDrv.cmd again to see if the definition of the drive letter was successful.
Calling up the UsrLogon.cmd logon script to assign the home directory to the defined drive letter. In this way, the generated drive letter can be used during the installation of the application.
The main goal of this script is to ensure that a drive letter is assigned to a user’s home directory. The status is verified with RootDrv.cmd. The home directory can be located either locally under %SystemDrive%\Documents and Settings\<UserName> or on a network resource. The drive letter makes sure that even older applications can access a home directory that was defined by a UNC name or is based on long paths. Regarding application file access, the drive letter is the smallest common denominator for execution on a terminal server.
A reference to application-specific tasks that need to be executed during user logon is created in a script named UsrLogn2.cmd by the compatibility scripts logic.
To reset changes made by installation scripts, please refer to the %SystemRoot%\Application Compatibility Scripts\Uninstall directory when uninstalling an application. This directory supplies a number of uninstallation scripts.
Let us assume that an authorized user Admin installs the application App on a terminal server. The application was programmed at a time when it was still unusual to access directories through the UNC name convention or with long path names. However, the installation program determines the user’s home directory by evaluating the %HomeDrive% and %HomePath% environment variables. The result is entered in the registry to define the paths for App for loading and saving data. It is highly possible that the long names lead to errors in the old applications.Two of the most important tasks of the scripts ChkRoot.cmd and RootDrv2.cmd introduced earlier are creating or verifying the %RootDrive% environment variable. Why is this environment variable so important for the applications on a terminal server? Let us take a look at a simple example to answer this question.
Assuming that the Admin’s home directory is on a file server on the network, the path could be X:\Admin. The home directory in the Admin’s account is determined by the assignment of \\Server\Share\Admin to the X: drive letter. On a terminal server, however, this entry is assigned to each user, which is not very plausible. Each user should have his or her own path for access to working files for App.
There can be users who do not have their home directory on the network. They use the Windows Server 2003 default setting. Their home directory is located under %SystemRoot%\Documents and Settings\%UserName%. For the user Tina, this would be C:\Documents and Settings\Tina. This, of course, looks completely different than X:\Admin. Table 7.3 shows the differences.
Documents and Settings\Tina
Even though no obvious mistake was made, the result is useless. If during the installation of App, the correct path (X:\Admin) is saved in the registry under, for example, the HKCU\Software\App\DefaultPath key, and this registry setting is mirrored in HKLM because of the installation mode, this data cannot be accessed by any other user.
The solution to this problem is the %RootDrive% environment variable. It represents a drive letter that can be freely selected and that has never been used by any other user before. The drive letter is fixed systemwide and is thus the same for all users. When a user logs on, his or her individual home directory %HomeDrive%%HomePath% is automatically assigned to the %RootDrive% drive letter.
When selecting the default drive letter W:\ as the %RootDrive% value, this entry must be saved in the HKCU\Software\App\DefaultPath registry value during the installationof an application. From that point on, each user accesses his or her home directory via the W:\ drive letter. The conflict is thus solved, and the old application needs to handle only one drive letter, W:\.
For the two users in the preceding example, the situation is now as follows:
Admin: W:\ = X:\Admin
Tina: W:\ = C:\Documents and Settings\Tina
%RootDrive% is linked to the user-specific home directory in the UsrLogon.cmd script that will be described in further detail later. The corresponding commands are Subst and Net. The latter is used only to cancel an already existing assignment of the drive letter to a shared network resource.
Net Use %RootDrive% /D >NUL: 2>&1 Subst %RootDrive% "%HomeDrive%%HomePath%" if ERRORLEVEL 1 goto SubstErr goto AfterSubst :SubstErr Subst %RootDrive% /d >NUL: 2>&1 Subst %RootDrive% "%HomeDrive%%HomePath%" :AfterSubst
With alternative script environments, such as Windows Script Host, some of these programming approaches will be easier. However, the behavior described here still needs to be rebuilt to achieve a correct behavior of many old Windows-based applications. If you prefer to work without an additional drive letter, you need to automate all user-specific path entries in the registry during logon for all applications installed.
If there is a home directory for each user on the network already, the following procedure is recommended: Format the part of Usrlogon.cmd shown in Listing 7- 4 as comments and set the letter for the home directory through the %RootDrive% variable in RootDrv.cmd. Further adjustments of the logon script subsequently have to ensure that all directories and files needed for the applications are located in the user’s home directory and not in the user’s profile.
Whenever a user logs on to a terminal server, a drive letter must be assigned to the user’s home directory to ensure proper operation of many applications. Additionally, the following application-specific tasks might need to be performed:
Generating subdirectories in the user’s home directory
Copying files from a central source to the home directory
Setting changed access permissions for certain files
All these tasks can be executed during user logon through the UsrLogon.cmd script. Each terminal server provides a number of application-specific standard logon scripts that are located in the %SystemRoot%\Application Compatibility Scripts\Logon directory.
You can verify or change the mandatory execution of the UsrLogon.cmd script in the registry under HKLM\Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Appsetup. Other keys for automated execution of scripts after predefined system events (such as user logon or user logoff) are listed in Chapter 6.
The UsrLogon.cmd command file is a specific solution for terminal servers. It is located in the %SystemRoot%\System32 directory and runs at the time of each user logon. UsrLogon.cmd mainly ensures that other scripts are called up that are needed for the adjustment of individual applications. This script also assigns each user a so-called “RootDrive” under a previously selected drive letter.
This script is all but trivial, so let me briefly list its individual functions:
Invoking the SetPaths.cmd script in the %SystemRoot%\Application Compatibility Scripts directory. This script generates environment variables from some registry entries so that the other scripts can be executed without hard-coded system paths. The scripts are thus independent of the system language. This particularly applies to start menus, autostart options, and the locations of system-specific files, templates, and applications. When it is done, SetPaths.cmd returns to UsrLogon.cmd.
Invoking the UsrLogn1.cmd script in the %SystemRoot%\System32 directory, if this directory exists. This script is responsible for all commands that are not dependent on the %RootDrive% environment variable and returns to UsrLogon.cmd when it is done.
Invoking the RootDrv.cmd script in the %SystemRoot%\Application Compatibility Scripts directory. In combination with the RootDrv2.cmd script, this script handles the assignment of a user’s home directory to a drive letter. When they are done, the scripts return to UsrLogon.cmd.
Assigning a user’s home directory to a drive letter that is defined through the %RootDrive% environment variable. The default home directory is the local user profile directory. If the home directory is located on the network, manual changes need to be performed in the UsrLogon.cmd script.
Invoking the UsrLogn2.cmd script. It contains commands that depend on the %RootDrive% environment variable. In particular, the installation scripts of applications write command sequences in UsrLogn2.cmd, defining necessary adjustment tasks that will be executed upon user logon.
Right after a terminal server is installed, some of the scripts described earlier do not exist yet. So how do they get on the system? How is the %RootDrive% environment variable that handles invoking other scripts generated? This is what the installation scripts described earlier are needed for: they generate scripts that can be invoked right then. This concept is not really the most intuitive way to create such a configuration, but it is compatible with many older Microsoft Windows versions and programs.
The logical sequence of the UsrLogon.cmd script is not easy to understand. Nevertheless, it is important to implement the required function for older Windows-based applications through default scripts. Here the differences between applications that are already compatible with Windows 2000 or Windows Server 2003 come to light because they do not need this type of scripts (for example, Microsoft Office 2000). Older applications need to be adjusted for Terminal Services first. The differences are so substantial that the complicated script mechanisms are needed to balance out the system.
For both application installations and user logon on a terminal server, scripts are invoked that call other scripts. The most important supporting scripts are briefly described in the following section.
While the other scripts already existed in the Windows NT 4.0 Terminal Server Edition, at least in some initial version, the SetPaths.cmd script was introduced only with Windows 2000. It still exists under Windows Server 2003 and handles the correct setting of environment variables during installation and user logon.
The drive letter for a user’s home directory is selected through the RootDrv.cmd script, as shown in Listing 7-5. This script is executed during application installation and user logon.
If Exist "%SystemRoot%\Application Compatibility Scripts\RootDrv2.Cmd" Call "%SystemRoot%\Application Compatibility Scripts\RootDrv2.Cmd"
Listing 7-5 seems to be very confusing. It shows the lack of power of the default commands in the command-line shell and the resulting tricks to work around this problem. The Rootdrv.cmd script is called from different places in other scripts, and it is used only to verify the existence of yet another script.
The real assignment of a letter to the %RootDrive% environment variable is done by the RootDrv2.cmd script, which is invoked by RootDrv.cmd, if it exists. Only through this cascaded invoking of scripts can conditional branches be achieved with default commands. Specifically because of such a complicated script hierarchy, the RootDrv2.cmd’s syntax is relatively simple.
After invoking RootDrv.cmd through the Call command, UsrLogon.cmd verifies if the letter is assigned to the %RootDrive% environment variable.
If "A%RootDrive%A" == "AA" End.Cmd
If this is the case, the letter in %RootDrive% is used for the user’s home directory. If not, the script ends immediately.
It is easy to imagine that the default prompt commands are insufficient for powerful scripts, such as the ones that meet the demands of compatibility scripts described here. This is why a number of additional command-line tools must be set up to achieve the required modifications in the registry, file system, and security settings. Some of these tools were developed especially for the terminal server; some have been known for a longer time from earlier Windows Resource Kits. The supporting tools are introduced in the following table.
This tool determines whether a predefined key and value exist in the registry. The result is redirected to a file that includes an environment variable and the associated registry value with a leading set command. The value must be a character string.
This tool performs simple search-and-replace actions in texts. It reads from an input file and writes to an output file. Each parameter can contain an environment variable.
This tool is used for .ini file updates.
This tool is located in the %Systemroot%\System32 folder. It reads key files and uses its values to modify registry keys.