Creating logon scripts with KiXtart, part 4

In this final installment of his series of Daily Drill Downs on KiXtart, Richard Charrington examines the KiXtart commands and functions you use to manipulate strings.

In part 1 of this series of Daily Drill Downs, I included background information on KiXtart, discussed common structures and commands, and provided several code examples. In part2 , I examined loops, subroutine calls, and the GoTo command. In part 3 , I showed you how to manipulate the DOS window, or console, that KiXtart runs in. I also demonstrated how to communicate with a user, map network drives, and handle input/output to the screen and files. In this installment, I’ll cover the commands and functions available in KiXtart for manipulating strings. I’ll finish off with some of the other useful functions you may use in your early scripts.

String manipulation
The most useful string function available in KiXtart is SubStr, which returns part of a string. You can also change the case of a string, get its length, eliminate leading or trailing spaces, and check to see whether one string can be found in another string.

As the name suggests, this function returns a part, or substring, of a string. The syntax is:
$Result = SubStr("string",start,length)
You can use these parameters with the SubStr function:
  • string: The string from which to extract a substring. String can be a variable or a literal.
  • start: The offset in the string where the substring begins.
  • length: The length of the substring.

UCase and LCase
These functions change the case of a string to all upper case (UCase) or all lower case (LCase). The syntax is:
$Result = UCase("string")
$Result = LCase("string")
Again, string may be a variable or a literal.

Ltrim and Rtrim
These functions are used to remove any leading or trailing spaces from a string. Ltrim would be useful for making the result of @IPADDRESS more like a normal IP address. (@IPADDRESS produces a string that always consists of four sets of three characters separated by periods—the IP address of, @IPADDRESS0 is 123. 45. 6. 7.)

The syntax of these functions is:
$Result = Ltrim("string")
$Result = Rtrim("string")
Here’s an example:
$x = 0
DIM $sub[3]
  $sub[$x] = Ltrim(SubStr($ip,($x*4)+1,3))
  $x = $x + 1
Until $x = 4
? $sub[0] + "." + $sub[1] + "." + $sub[2] + "." + $sub[3]
Okay, I’ve thrown in a couple of new things here, so let me explain. As I mentioned earlier in this series, variables do not have to be declared. However, arrays must be declared. So, in line two of this example, I declare an array of four elements (arrays begin with element 0), which I use to hold the four octets of the IP address.

Also, in the first line of the Do loop, I have nested the SubStr function inside the Ltrim function. This arrangement is quite acceptable and makes for more compact code.

Notice that I assigned the result of @IPADDRESS to a variable. This is because @IPADDRESS is a function and, if used within the Do loop, would be executed four times. Assigning it to a variable means that it’s executed only once.

This function simply returns a number representing how many characters exist in a string. Its syntax is:
$l = Len("string")
The string parameter, in this case, would very likely be a variable, because you’d already know the length of a literal when you wrote the code.

This function is used to check whether one string can be found within another. Its syntax is:
$Position = InStr("does_this_string","contain_this_string")
The function returns 0 if the first string doesn’t contain the second string. Otherwise, it returns the start position of the second string within the first.

Here are some examples:
; Check if @IPADDRESS contains the subnet 192.168.10
if Instr(@IPADDRESS,"192.168. 10")
  ? "You are in the correct subnet"

;Extract the first part of a string
$pos = InStr($word,"-")
$start = SubStr($word,1,$pos-1)
Although it isn’t really a string manipulation function, I’m including Chr here for completeness. Chr returns the character representation of an ASCII code. The syntax is:
The number parameter is any character from 0 to 255.

Some characters are non-displayable and result in actions—such as Chr(7), which is the BELL character, and Chr(12), which is FORMFEED. Be sure to specify displayable characters only.

Some more on files
In addition to file input/output, KiXtart provides functions that enable you to check out the details of given files. In this section, I’ll describe those functions.

Exist is simply a function that checks whether a file exists. It works in much the same way as the command-line If existfilename command. As with the command line, it’s not a function that does anything in isolation; rather, it must be used with an If, While, or Until command. For example:
If exist("c:\test.txt")
  del "c:\test.txt"
If exist("c:\test.txt") = 0
  copy "z:\test.txt" "c:\"
As you can see, the function returns 0 if the file cannot be found. Otherwise, it returns 1.

Very much like the DOS command ATTRIB, this command returns the attributes set on a given file. Unlike the DOS command, GetFileAttr doesn’t accept wildcards.

The function returns the following values:

1 Read only The file or directory is read-only. Applications can read the file but cannot write to it or delete it. In the case of a directory, applications cannot delete it.
2 Hidden The file or directory is hidden. It is not included in an ordinary directory listing.
4 System The file or directory is part of, or is used exclusively by, the operating system.
16 Directory The filename identifies a directory.
32 Archive The file or directory is an archive file or directory. Applications use this attribute to mark files for backup or removal.

A number of other attributes can be returned. Please refer to the KiXtart documentation for details. The syntax for the GetFileAttr command is:
$value = GetFileAttr("filename")
To test for a specific attribute, you’ll need to use logical AND. Here’s an example:
$value = GetFileAttr("c:\bootlog.txt")
? "Attributes for c:\ bootlog.txt:"
? " "
case $value AND 1
  $value = $value OR 1
case $value AND 2
  $value = $value OR 2
case $value AND 4
  $value = $value OR 4
case $value AND 32
$value = $value OR 32
until $value = 0
The output from this code would be:
Attributes for c:\bootlog.txt:
As usual, if the function fails (if, for instance, the file doesn’t exist), @ERROR will be set to the error code.

This is the reverse of the previous function. Provided you have the relevant permissions, it allows you to change the attributes set on a specified file. Its syntax is:
As with the previous function, the attributes are represented by the following values:

1 Read only
2 Hidden
4 System
32 Archive
128 Normal (This value resets [switches off] all attributes, and only makes sense if used alone.)

Again, a number of other attributes can be set, so please refer to the KiXtart documentation to learn about them.

If the function fails, @ERROR will be set to the error code.

This function does exactly what it says: It returns the exact size, in bytes, of the specified file. Its syntax is:
This function won’t work on any file that’s in use, such as Win386.swp in Windows 9x.

This command returns the date/time stamp from the specified file. The string returned is in the format of "YYYY/MM/DD HH:MM:SS". Its syntax is:
If you’re proposing to do some dynamic updating, you may need to check whether the files you’re updating already exist and whether they’re older than the files you’re updating them with. I’ve already covered the Exist function, which provides the first check. The CompareFileTimes function provides both checks (an error will be returned if you try comparing files that don’t exist). The syntax is:
$result = CompareFileTimes("filename1","filename2")
The result value returned will be one of the following:

-3 Filename2 could not be opened.
-2 Filename1 could not be opened.
-1 Filename1 is older than Filename2.
0 Filename1 and Filename2 have the same date and time.
1 Filename1 is more recent than Filename2.

@ERROR will contain the error code if either file cannot be opened. Here’s an example:
$Result = CompareFileTimes(@LDRIVE + "\Kix32.exe", "C:\WINDOWS\Kix32.exe")
If $Result = 1 OR $Result = -3
  COPY @LDRIVE + "\Kix32.exe" "C:\WINDOWS"
This example shows that the single function can achieve both the checks I mentioned earlier: It checks to see whether the destination file exists. If that file does exist, the function checks that the destination file is older than the source file. It will copy (update) the file only if both checks are true.

This function is somewhat more complex than the previous functions. It allows you to get version information from a file. Rather than returning all the version information and leaving it to the programmer to disassemble it, the function allows you to specify which field you want to extract. The syntax is:
where filename identifies the file for which you want to get the version string and versionfield is an optional parameter identifying the specific version information field that should be retrieved. Possible values for this field are:
  • Comments—Contains any additional information that should be displayed for diagnostic purposes.
  • CompanyName—Identifies the company that produced the file. Example: "Microsoft Corporation" or "Standard Microsystems Corporation, Inc."
  • FileDescription—Describes the file in such a way that it can be presented to users. This string may be displayed in a list box when the user is choosing files to install. Example: "Keyboard driver for AT-style keyboards" or "Microsoft Word for Windows."
  • FileVersion—Identifies the version of this file. Example: "3.00A" or "5.00.RC2."
  • InternalName—Identifies the file's internal name, if one exists. For example, this string could contain the module name for a dynamic link library (DLL), a virtual device name for a Windows virtual device, or a device name for an MS-DOS device driver.
  • Language—Provides the full English name of the language of the file specified in the format defined by ISO Standard 639. Example: “0413Dutch (Standard)."
  • LegalCopyright—Describes all copyright notices, trademarks, and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, trademark numbers, and so on. In English, this string should be in the format "Copyright Microsoft Corp. 1990-1994."
  • LegalTrademarks—Describes all trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. In English, this string should be in the format "Windows is a trademark of Microsoft Corporation."
  • OriginalFilename—Identifies the original name of the file, not including a path. This enables an application to determine whether a file has been renamed by a user. This name may not be in the MS-DOS 8.3 format if the file is specific to a non-FAT file system.
  • PrivateBuild—Describes by whom, where, and why this private version of the file was built. Example: "Built by OSCAR on \OSCAR2."
  • ProductName—Identifies the name of the product with which this file is distributed. For example, this string could be "Microsoft Windows."
  • ProductVersion—Identifies the version of the product with which this file is distributed. Example: "3.00A" or "5.00.RC2."
  • SpecialBuild—Describes how this version of the file differs from the normal version. Example: "Private build for Olivetti solving mouse problems on M250 and M250E computers."

If the VersionField parameter is omitted, then FileVersion will be returned by default.

The information returned by this function is the same as the version information displayed in Windows Explorer.

This function applies only to 32-bit Windows-based executable files.

And finally…
Finally, I’ll take a look at a couple of other useful functions: SetTime and LogEvent.

SetTime is equivalent to the DOS command NET TIME /SET /YES. The system clock of the local machine is set to the time on a specified source. The syntax is:
SetTime "string"
where string can be one of the following:
  • Servername—A UNC path to a server. The time is taken from the server's system clock.
  • DomainName—The name of a domain. The domain is browsed for a server providing the TimeSource service.
  • *—The local domain is browsed for a server providing the TimeSource service.

On Windows NT, SetTime requires the current user to have the Change The System Time privilege.

This is one of three functions that operates on the Windows NT event log. For the purposes of this Daily Drill Down, I am only including this one because it is the one you are most likely to use when writing logon scripts. LogEvent can be used to record the progress, success, or failure of a logon script, although recording progress and/or success would mean that the event log would quickly fill up.

For obvious reasons, event log functions will work only on Windows NT systems. The syntax is:
where type represents the type of event you want to record; ID is the number representing the event that occurred; message is the message text of the event; target is an optional parameter representing the UNC name of the system where the event should be logged (by default, all events are logged on the local system); and source is an optional parameter representing the source of the event (if this parameter isn’t specified, KiXtart will assume that Kix32.exe is the source of the event).

Possible values for type include:
  • 1—ERROR

Here’s an example:
$RC = LogEvent( 1 , 20 , "Logon script failed for @USERID on @COMPUTERNAME" , @LSERVER )
If something happened during the execution of the logon script that meant you had to stop further processing, the above example would enter an ERROR event (with an ID of 20) in the event log of the logon server. (The logon server is the one currently servicing the logon of this user.) This helps you identify the point in the logon script that the failure occurred. For tracking purposes, the message text includes the user's account and the name of his/her computer.

There’s a lot more to KiXtart than I’ve covered in this series of Daily Drill Downs. As I’ve mentioned before, the KiXtart package comes with a document in excess of 100 pages. My goal with this series has been to introduce you to this extremely useful scripting language and help you get started writing your own scripts.

Richard Charrington’s computer career began when he started working with PCs—back when they were known as microcomputers. Starting as a programmer, he worked his way up to the lofty heights of a Windows NT systems administrator, and he has done just about everything in between. Richard has been working with Windows since before it had a proper GUI and with Windows NT since it was LANManager. Now a contractor, he has slipped into script writing for Windows NT and has built some very useful auto-admin utilities.

The authors and editors have taken care in preparation of the content contained herein, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.

Editor's Picks

Free Newsletters, In your Inbox