So you've tried KiXtart, and you like the results. You're not alone. Many serious Windows NT administrators keep KiXtart in their toolbox. At this point, you might be asking yourself, "What else can KiXtart do to make my job easier?"

In an NT or Windows 95 environment, the Registry controls the user environment. Much of KiXtart's power lies in its capability to change the Registry. With KiXtart, you can customize the user environment without visiting every user machine. For example, you can change the default file location for applications and force all Win95 machines into a certain workgroup. You can also use KiXtart to help you automate your administration tasks, such as determining which service packs and hotfixes are on your NT machines.

In "Creating Logon Scripts with KiXtart" (February 1999), Gregg Branham explained the basics of KiXtart and how to use KiXtart to create a logon script. In this article, I'll introduce you to some intermediate KiXtart scripting techniques. I'll focus on two scripts: Tasks.kix and PatchLevel.kix. Both of these scripts demonstrate Registry manipulation. Patchlevel.kix also illustrates file I/O. I used KiXtart 3.51 to write both scripts. Although the Microsoft Windows NT Server 4.0 Resource Kit includes KiXtart, I recommend that you download the latest version from

Intermediate KiXtart Scripting
The KiXtart functions that you use to manipulate the Registry aren't hard to learn. Commonly used KiXtart Registry functions include ReadValue and WriteValue, which let you read and write Registry key values. The KiXtart download comes with kix95.doc, the KiXtart documentation that includes a complete listing of available functions.

The tricky part about using scripts to manipulate the Registry is finding the values, keys, and data that you want to change, add, or delete. If you're new to the Registry, you might think that this task is impossible. Knowing how the Registry is set up can help. The Registry has two distinct sections: the HKEY_LOCAL_MACHINE area, which contains all information that is machine-specific, and the HKEY_USERS area, which contains information that is user-specific. You can use several aliases to access the Registry. For example, the HKEY_CURRENT_USER alias represents the settings for the current logged-on user. The HKEY_ CURRENT_USER alias is the easiest method for modifying user-specific data.

Some good resources to help you navigate through the Registry are Tim Daniels' 1001 Secrets for Windows NT Registry (29th Street Press, and Sandra Osborne's Windows NT Registry (MacMillan Publishing). Another resource is Mark Russinovich and Bryce Cogswell's Regmon utility ( This utility monitors all Registry activity on NT and Win9x. After you install Regmon, you make the changes to the Registry that you want your script to make and watch the results. For example, to find the values for the default file locations in Microsoft Office 97, I loaded Regmon and changed the paths in Word, Excel, Access, and PowerPoint. Regmon then displayed the parameters I changed in the Registry. Armed with the parameters to change, you're ready to write your KiXtart script.

You've probably heard many horror stories about people crippling their NT or Win95 machines because they made incorrect Registry changes. Although incorrect changes are a possibility, you can minimize the risk in two ways. First, be sure you know the effects of the changes you're making. Second, either use a nonproduction machine to test your script or back up the Registry before running your script. If you need help backing up your NT Registry, see Bob Chronister, "Ask Dr. Bob Your NT Questions," Windows NT Magazine, April 1998. If you need help backing up your Win95 Registry, see the Microsoft article "How to Back Up the Registry" ( articles/q132/3/32.asp).

The Tasks.kix Script
As a consultant, I usually inherit a network that needs improvement. During initial consultation with one company, I noticed that its network had a workgroup for every division, no matter how small. In all, the network had 20 workgroups, each containing between 5 and 10 Win95 machines. Although this setup presented users with a logical view from Network Neighborhood, it also meant that a Win95 machine was the segment master browser (SegMB). (For more information about SegMB, see Bob Chronister, "Ask Dr. Bob Your NT Questions," Windows NT Magazine, September 1997.) Using a desktop machine as a SegMB isn't a good idea. When that user goes home, he or she will likely turn off the machine, causing an election on the network, which generates unnecessary traffic.

I decided to consolidate all the Win95 machines into a workgroup called ATL, which is the name of the company's NT domain. With this setup, the NT servers could maintain the browse list on the network and generate less network traffic.

After I found the correct Win95 Registry values to change, I wrote the Tasks.kix script in Listing 1. Although KiXtart is case-insensitive, this script uses uppercase for commands, title case for functions, and lowercase for macros to help you differentiate between these components. The script has two parts. Part 1 forces Win95 machines into the ATL workgroup and disables the Win95 browser service. Part 2 sets the default file locations in Office 97. Here's how you create this script.

Part 1. You begin Part 1 with the @inwin macro. If you set this macro to the value of 2, the script implements the changes only on Win95 machines. If you set this macro to the value of 1, the script implements the changes only on NT machines. You can't apply the code in Part 1 to your NT clients. This code doesn't work on NT for two reasons. First, Win9x and NT have different Registry structures, which means that the data you want to change isn't in the same location on both platforms. Second, Win9x and NT have different security setups. One of NT's strengths is built-in security. Under Win95, the user has permission to access and change any part of the Registry. Under NT, permissions limit the Registry changes that a user can make. A safe assumption to make for NT systems is that users can change only their profile located under the HKEY_CURRENT_USER entry point.

After you set the @inwin macro to 2, you use the ReadValue function to read the specified Win95 Registry value. The ReadValue function has the syntax

                              ReadValue("key path", "value")                              

In this case, the "key path" parameter is "HKEY_LOCAL_MACHINE\ SYSTEM\CurrentControlSet\ Services\VXD\VNETSUP" and the "value" parameter is "Workgroup". You then set the ReadValue function's results (i.e., the Workgroup value) to the $Workgroup variable.

Next, you apply the IF ELSE ENDIF command to test whether the Workgroup value is ATL. If the value is ATL, you take no further action on the $Workgroup variable. If the Workgroup value isn't ATL, you use the WriteValue function to set this Registry value to ATL. The WriteValue function's syntax is

                              WriteValue("key path", "value", "data", "data type")                              

In this case, the "key path" and "value" parameters are the same as that in the ReadValue function; the "data" parameter is "ATL" and the "data type" parameter is "REG_SZ". You set the WriteValue function's results to the $Hidden variable.

You then follow the same procedure to disable the Win95 machines' browser service. You use the ReadValue function to read the current MaintainServerList value in the Win95 Registry and set that value to the $Browser variable. If the MaintainServerList value is 0 (i.e., disabled), you take no further action on the $Workgroup variable. If this value is 1 (i.e., enabled), you use the WriteValue function to set the MaintainServerList value to 0 and set that value to the $Hidden variable.

Under Win95, changing the Workgroup value and disabling the browser service requires a reboot to take effect. Although KiXtart has a shutdown command, it only works reliably on NT. Therefore, if either parameter changes, users receive a message asking them to shutdown and then restart their computer. To send this message to the appropriate users, you use the IF THEN ELSE command with the MessageBox function. If the $Browser variable is 0 and the $Workgroup variable is ATL, users don't receive the message. Otherwise, they do.

Part 2. The second part of the Tasks.kix script contains the code to set the default file locations in Office 97. Because Part 2 changes data under the HKEY_CURRENT_USER entry point and because the location of the Registry entry you're modifying is consistent across platforms, the code applies to both Win95 and NT. Thus, you don't need to include the @inwin macro. Instead, you immediately begin the code to change the default file location for Word. You use the WriteValue function to insert the appropriate changes into the Registry. The WriteValue function's "data" parameter contains the new default file location, H:\. You use the same procedure to change the default file locations for Excel, Access, and PowerPoint. Notice the empty quotes in the "value" parameter in the PowerPoint code. The use of empty quotes isn't an error. The developers at Microsoft choose to use a value with a null name.

The Tasks.kix script is part of my standard logon script. You can easily add Tasks.kix to other logon scripts. For example, you can add Tasks.kix to the logon script in "Creating Logon Scripts with KiXtart" to extend its functionality.

Keep in mind that modifying the Registry can be dangerous to your OS's health. KiXtart doesn't warn you before a script writes or deletes a value. You need to thoroughly test your logon script before you run it. If you still feel uncomfortable with Registry access, have your first script only read the Registry. Read-only access is safe.

The PatchLevel.kix Script
Now that you have seen a few Registry manipulation examples, you can tackle a more complex script that you can use as a standalone administration tool. The PatchLevel.kix script determines which hotfixes and service packs are on your NT machines and generates a Web page as output. This script was the inspiration for SPCheck (, a popular tool that performs the same task.

To make the PatchLevel.kix script easier to read, it contains the MAIN section (which controls the overall script execution) and several subroutines (i.e., HTML_PART_1, HTML_PART_2, and PATCHLEVEL). Because of the script's length, I haven't included all the subroutines in this article. However, you can find the complete PatchLevel.kix script on the Win32 Scripting Journal Web site or on my Web site (

The MAIN section in Listing 2 begins with the file I/O function RedirectOutput to generate your Web page. This function pipes standard output to a file instead of the screen. The RedirectOutput function's syntax is

                              RedirectOutput("filename", overwrite)                              

The "filename" parameter contains the name of the file to which you want to redirect the output. In this case, you're redirecting the output to "@scriptdir\default.htm". Default.htm is the file, and the @scriptdir macro specifies that this file is in the same directory from which you called the script. The optional overwrite parameter specifies whether you want the redirected output to append to (value of 0) or write over (value of 1) any existing data in the file. In this case, you want to overwrite any existing data in the default.htm file.

Next, the MAIN section uses the GOSUB command to execute the HTML_PART_1 subroutine in Listing 3. This subroutine prints out a simple HTML header for the Web page. You can dress up the header with the optional graphic of two networked computers. (You can find this graphic, Network.gif, on the Win32 Scripting Journal Web site or on my Web site.)

A question mark (?) in front of each line in the subroutine writes a new line to the standard output. The new lines make the HTML output easier to read. The extra spaces in the script also make the HTML output more readable. The chr(34) allows KiXtart to write double quotes in the standard output, which the HTML code requires.

If you want to modify the Web page output, you can create HTML code by hand or with a tool such as Microsoft FrontPage. The only stipulation is that you must replace any double quotes in the HTML code with chr(34).

The HTML_PART_1 subroutine ends with the RETURN command. This command tells the script to continue at the line after the GOSUB "HTML_PART_1" command in the MAIN section.

With the HTML header in place, your script can now process the machine information. You can specify which NT machines to query in several ways. For example, you can create values in the Registry or use a text file to hold the machine names. I prefer to use a text file, because you can copy the script to a disk and carry it with you without having to initialize values in the Registry. Editing a text file is also easier than editing the Registry. The text file must contain only the names of the NT machines you want to check. Each name needs to be on a separate line followed by a carriage return. For example, the machines.txt file for the PatchLevel.kix script looks like

                              HALO                              BINTFA                              BINTPX                              BINTXS                              

You use the Open function to read the machines.txt file. This function's syntax is

                              Open(file number, "file name", mode)                              

The file number parameter specifies the number of the file you want to open. KiXtart lets you have up to 10 open files, so the possible values range from 1 to 10. The file number for machines.txt is 1. The "file name" parameter specifies the file's path and name. In this instance, you're opening the machines.txt file, which is in the same directory as the PatchLevel.kix script. The optional mode parameter tells the script what to do if it can't find the file and, if it finds the file, whether to allow read or write access to it. If you don't specify the mode, you get the defaults of having the Open function fail if the script can't find the file and opening the file for read access.

You use the Open function with the IF THEN ELSE command. If the Open function succeeds (which = 0 specifies) the script performs two tasks. First, it sets the $MainError variable to the @error macro. This macro represents the return value of the most recent function or command. A value of 0 means the function or command has succeeded; any other value returns an error code. Second, the script goes into the WHILE ­ LOOP command, which contains a series of statements. The script proceeds through the statements as long as they are true.

In PatchLevel.kix, if the Open function succeeds, the script uses the ReadLine function to read the lines in machines.txt. The number in parentheses after ReadLine specifies the file number and not the line number. To the ReadLine function, a line is a string followed by a carriage return. If ReadLine successfully reads the first line in machines.txt (i.e., returns a value of 0), the script uses the GOSUB command to execute the PATCHLEVEL subroutine. If this subroutine is successful, the script loops back to the second line in machine.txt. This process continues until the end of the machine.txt file.

The PATCHLEVEL subroutine in Listing 4 on page 5 polls the NT machines to determine their service pack number and hotfixes. Starting with Service Pack 4 (SP4), Microsoft changed the Registry location of the hotfix information. The PATCHLEVEL subroutine handles this change crudely. It first polls the pre-SP4 location for hotfix information and then polls the SP4 location. For pre-SP4 hotfixes, the script simply displays the associated Knowledge Base number. For SP4 hotfixes, the script appends an SP4\ before the associated Knowledge Base number.

Here's how the PATCHLEVEL subroutine works. After the subroutine prints the machine's name, it uses the ReadValue function to determine the machine's service pack number. The IF ELSE ENDIF command that follows tells the script to print the service pack number if a service pack has been installed on the machine. If a service pack hasn't been installed on the machine, the script prints No Service Pack.

The PATCHLEVEL subroutine then uses the EnumKey function to dynamically list all the hotfixes that are on that machine. This function has the syntax

                              EnumKey("key name", "index")                              

The "key name" parameter specifies the name of the Registry key that contains the subkey you want to enumerate. The "index" parameter is a numeric value that represents the position of that subkey. The EnumKey function lists the subkeys available based on that index value. In the PATCHLEVEL subroutine, the index value is the $Index variable. Using a variable rather than a numeric value is acceptable because you set this variable to 0 before using it.

The PATCHLEVEL subroutine includes two loops: Loop1 and Loop2. Loop1 retrieves the Knowledge Base number and description for all installed post-SP3 and previous hotfixes. Loop2 retrieves the Knowledge Base number and description for all post-SP4 hotfixes.

The PATCHLEVEL subroutine ends with HTML formatting code, followed by the RETURN command. The RETURN command instructs the script to continue at the line after the GOSUB "PATCHLEVEL" command in the MAIN section.

Finally, after all the machines listed in machines.txt have been queried, you close the script by running the HTML_PART_2 subroutine, which writes the footer for your Web page.

A Useful Overall Scripting Tool
The Tasks.kix and PatchLevel.kix scripts illustrate KiXtart's usability not only as an enhanced logon script processor, but also as an overall scripting language. Now that you've learned a few more KiXtart scripting techniques, you're ready to start exploring all the ways that KiXtart can make your job easier.