Scripting power in a simple package

Logon scripts can provide a centrally controlled method for a variety of everyday administrative tasks that you would otherwise need to perform manually at users' desktops. Such a method is especially useful in a WAN environment. KiXtart, an invaluable single-source processor for advanced logon scripts, provides a much more robust environment and toolset than does Windows NT's built-in, DOS-like batch-command processor. KiXtart's many features let you return NT SAM or system information, manipulate files, modify the registry, and perform OLE automation tasks. (KiXtart is also an excellent choice as a batch-command processor. You can use the tool with Windows 2000's or NT's AT command to create extremely complex and useful server-side tools.) KiXtart provides flexibility in calling scripts and subroutines according to a user's identity and group affiliation, so you can use one script that calls other scripts as needed. This approach centralizes script control and simplifies troubleshooting and maintenance.

To truly garner the power and usefulness of logon scripting, you must take a holistic approach. Functional snippets of script in a randomly built and poorly conceived environment are like Band-Aids on a broken arm. With some creative planning and a standards-based approach to user storage and security-group naming conventions, though, you can create KiXtart scripts to perform a variety of tasks that can greatly simplify administration. And proper use of KiXtart's features can help you not only reduce visits to individual desktops but also impose standards and quickly alter the desktop-computing environment across your enterprise. (For information about KiXtart's currently available version and other resources, see the sidebar "KiXtart's Origins.")

Setting Up KiXtart
The basic setup for KiXtart is extremely simple. KiXtart is available as part of the Microsoft Windows 2000 Resource Kit, or you can download the most recent version and related documentation from Place the KiXtart executable (kix32.exe) on the \netlogon share of any server that provides authentication services. (KiXtart requires additional setup on Windows 9x systems to permit those systems to communicate properly with the KiXtart remote procedure call—RPC—service. You need to install the RPC service on each domain controller—DC—and place the KiXtart helper DLLs—kx95.dll, kx16.dll, and kx32.dll—with the kix32.exe file on the \netlogon share. The RPC service executable, kxrpc.exe, comes with the KiXtart download.) For the most efficient setup, you need to consider a few additional factors, such as whether users access the WAN through dial-up or VPN connections. The KiXtart documentation covers such scenarios in detail.

The examples in this article assume that each script resides in the \netlogon share and uses the standard .kix extension. However, I create a \kixwork folder on my local drive for development and testing purposes. After I test my scripts, I distribute them to all DCs. These examples run under KiXtart 2001 and KiXtart 95 3.63. An enhancement to KiXtart 2001 provides the ability to run scripts without opening a script window; earlier versions required you to use the SETCONSOLE("hide") function to achieve this result. When testing scripts, however, you want to be able to see errors and output, so run the scripts in a command window.

Writing Scripts
After the KiXtart files are in place, you're ready to write your first script. KiXtart script files are basic text files with a .kix extension, so you can use Notepad or another text editor to create and modify your scripts. To call KiXtart scripts during user logon, use the Logon Script setting in the user's account profile. You can refer to a batch file that calls the KiXtart executable and references the initial script as a command line, but I prefer to refer to kix32.exe as the script to run. When you reference kix32.exe with no parameters, KiXtart looks by default for a script named kixtart.kix. You can call all your other scripts through this script, which serves as a centralized master script.

KiXtart's robust feature set and simple development environment can be extremely powerful in the hands of a developer. The language contains a fair sampling of features, including script control constructs, commands, functions, variables, and arrays. (You don't need to be a developer to take advantage of this tool, but an understanding of basic programmatic constructs is helpful. The Web-exclusive sidebar "KiXtart Scripting Basics" at, InstantDoc ID 25279, provides a rundown.)

To create more readability and reduce the overall size of your scripts, KiXtart lets you call other scripts from within a script. The calling script stops running and branches to the new script. After the commands from the new script have finished, control returns to the calling script. Listing 1 and Listing 2, and Listing 3 on page 12, provide a simple example of this functionality.

The user's logon script calls main.kix, which Listing 1 shows. Main.kix first performs some basic evaluations. The script starts by using the macro @MDAYNO to place the day of the month in a variable ($dayno). A simple If Else Endif construct determines whether the $dayno variable contains a value of less than 15 (i.e., whether the day is earlier than the 15th of the month); if so, main.kix calls script1.kix, which Listing 2 shows. After script1.kix completes, or when main.kix doesn't call script1.kix, main.kix calls script2.kix, which Listing 3 shows. After script2.kix completes, control returns to main.kix and a final message box appears. To test the functionality of these scripts, type

kix32.exe main.kix

KiXtart also lets you check the value of the @ERROR macro. You then can use that information to determine whether commands have succeeded or to discover whether functions have encountered specific errors. (Most KiXtart functions return an error code, as well.) The examples in this article, however, highlight KiXtart's core functionality and its use within a WAN environment rather than on error handling. For a more detailed explanation of KiXtart error handling, refer to the tool's documentation or one of the Web sites listed in "KiXtart's Origins."

Putting KiXtart to Work
The sample scripts in Listing 1, Listing 2, and Listing 3 are good but do little more than demonstrate program functionality, similar to the proverbial "hello world" example found in almost every programming tutorial. How can you take this functionality and apply it to a real-world environment?

The following example is based on an actual network-integration job for a company with four offices around the United States and Mexico. The goals were to provide an environment in which users had access to appropriate resources and to simplify universal access to PC-related data. A standard approach to the naming of server shares, security groups, and servers made logon scripts WAN-aware. The ultimate result was that administrators could handle most changes to a user's desktop environment through User Manager for Domains rather than through a trip to the user's local machine.

For the sake of this demonstration, my sample WAN has three locations: a headquarters in Chicago, a branch office in Los Angeles, and a branch office in New York City. I've given each office a three-character location code: CHI (for Chicago), LAS (for Los Angeles), and NYC (for New York City). The sample WAN is built on one NT 4.0 domain with a PDC and BDC in Chicago and BDCs in both branch offices. All servers referenced in the sample scripts have a primary function of file server and a role of DC. The primary file servers in each location use the following naming convention: location code + primary function + role + a two-character numerical ID. The Chicago PDC is named CHIDC01 (and performs only authentication services), the Chicago BDC is CHIFSDC02, the Los Angeles BDC is LASFSDC01, and the New York BDC, which isn't referenced in the sample scripts, is NYCFSDC01.

I used a similar approach when naming NT security groups and shares. Few administrators use the ability to assign a primary group in Win2K or NT environments. (The user account Primary Group attribute was originally designed to support Macintosh clients and POSIX compliance.) By default, all users are part of the Domain Users group, which becomes their default primary group. However, the KiXtart macro @PRIMARYGROUP can return this attribute, so when you assign each user a specific primary group, you can use that group to gain insight about users. For this example, I set the primary group for each user to the appropriate location and department, according to the naming convention location code + department. For example, users in New York's Sales department have the primary group _NYC_dptSales. The first set of characters specifies the location, and the second set specifies the department. The dpt prefix in the second set specifies that this group is a departmental group; an additional prj prefix in the second set would specify a project group.

I created a structure for data on each server. The structure lends itself to effective scripting and simplifies administration. If your company uses a different standard, you probably can alter the sample scripts to account for that standard. If your company doesn't have a standard for the location of user data or the location and name of network shares, consider creating one. The sample data structure establishes the following folder hierarchy:

Driveletter:   Data      Departments         Sales\  \[shared as dptSales\]
         Engineering\  \[shared as dptEngineering\]
         HumanResources\  \[shared as dptHumanResources\]
         Accounting\  \[shared as dptAccounting\]
         Finance\  \[shared as dptFinance\]
      Projects         Projectname1\  \[shared as prjProjectname1\]
         Projectname2\  \[shared as prjProjectname2\]
      Users         UserID1\  \[shared as zhmUserID1$\]
         UserID2\  \[shared as zhmUserID2$\]

Placing this structure below a data subfolder creates a simple mechanism for locating and moving information, if required. I created shares on subdirectories, as specified in brackets, then used the appropriate group to set security on each share. For example, the dptSales share's permissions would permit access only to the _LOC_dptSales group (where LOC is the location code pertaining to the server). If I needed to give each location's Sales group access to the sales share on each server, I could give access to a local domain group containing the global groups. Still using a location-specific group, however, let me determine each user's home server. I used this information later to map each user's user share and primary departmental share. Although Win2K and NT let you create a user's home directory in the user's profile, actually creating the individual user's share is helpful. Using the zhm prefix ensures that all user shares show up together in Server Manager (or any alphabetized list). Because user shares are specific to a user, I didn't want to encumber the browse list with several hundred names. Therefore, I appended the dollar sign ($) to the name to hide the share. This methodology might not be well suited to extremely large environments because of the number of user shares required, but utilities are available to help automate the creation of user-specific shares.

Web Listing 1 (, InstantDoc ID 25276) shows the sample script kixtart.kix. This script first defines the key variables used throughout the script. I store KiXtart macro values in variables for two reasons. First, the KiXtart macros reference and use information from the NT SAM database, so referencing them only once requires the least amount of traffic between client and server. (I've heard, however, that the benefit on a switched network is negligible.) Second, using variables is good form for application development. Although KiXtart isn't a full-fledged application-development tool, a good practice is still a good practice.

The script implicitly declares each variable, so the variables have Global scope (see "KiXtart Scripting Basics" for more information about variable scope). From the primary group, the script derives the variables that define location code, primary group, and home server. The script then uses this information to create variables containing the user's home share and department share. Next, the script begins mapping drives, according to the information stored in the variables. In each case, the script uses the EXIST() function to test the existence of the required resource. The script then calls msoffice.kix, which Web Listing 2 (, InstantDoc ID 25276) shows.

Like kixtart.kix, msoffice.kix begins by setting necessary variables. Msoffice.kix then ensures that each user has a My Documents folder, with subdirectories for Microsoft Word, Excel, and PowerPoint, on his or her user drive. If these folders don't exist, the script creates them. The script then edits the registry, pointing the Microsoft Office applications to the appropriate folder. In this script, I've hard-coded the base drive to correspond to the drive mapped to the user share in kixtart.kix. Control is then returned to kixtart.kix, which presents a message box containing information about the logon session.

Working in Your Environment
Your environment might differ from my example, but you can modify and effectively use these scripts. (For suggestions, see the Web-exclusive sidebar "5 Tips for Scripts" at, InstantDoc ID 25434.) I've used KiXtart for such projects as enabling DHCP on statically addressed workstations and assisting in the post-processing of imaged workstation deployment; I've also used the tool as a batch-command processor on my company's servers. KiXtart is an excellent resource for network administration and desktop automation.