KiXtart Starter's Guide.

Posted with permission.

Thanks to Bryce!

MS-Word Version of this document is available within this archive.

KIX Starters Guide

This is a work in progress 9/21/2000 9:40 AM……..

1. An introduction to KIX
A. "Hello World!"

2. How to run your KIX Script
A. Choose your OS Please….
1. Win9x
2. NT
B. From a Command line
C. From a batch File
1. Advanced Logon.bat
D. The netlogon folder
1. The KIXRPC Service.
2. How to get all your Domain controller's in a row
a. The Microsoft way.
b. Just Copy it by hand.

3. Basic SYNTAX
A. IF … Then / Select Case
B. Nested
C. $Variables

4. Macros
A. @error @serror
B. Other helpful macros

5. Return Codes
A. How to use them
B. Error checking

6. This piece of @#&^! Won't run!
A. BAD CODE!!! BAD CODE!!! Now go stand in the corner!

7. Basic Logon Script


1. An introduction to KIX


KixTart is a 32bit-script language that many people use as a logon script for their NT networks. It also can be thought of as a batch file on steroids, having many uses beyond a mere logon script.

The purpose of this document is to lend a helping hand to a newcomer, with tip and tricks that will help you use Kix for you own personal needs. It is meant to complement the manual "Kix95.doc" not replace it.

I strongly suggest that you print and place the Kix manual in a binder and keep it near your desk at all times!

Code/batch files will be designated with a beginning --------start-------- and an ending --------end--------
Anything between these two markers will be KIX code / Batch File.

Example:
;--------start--------
Kix code here


…….

;-------- end -------

A. "Hello World!"

First lets do a simple Kix script, to give you an Idea how easy this script language can be.

Run a DOS prompt.
Go to the directory where you have the KIX32.EXE file located. And type this

notepad hello.kix

this will launch Notepad.exe and it will ask you if you want to create a new file, answer yes.

Inside Notepad type the following

;--------start Hello.kix--------
"Hello World"
;-------- end Hello.kix--------

save "hello.kix" and close notepad.

At the DOS prompt type

Kix32 hello

You will get the following display.

U:\>kix32 hello

Hello World
U:\>

Congratulations! You have just ran you first KIX code.

2. How to run your KIX Script

There are a number of ways to run your Kix script. In the following chapter we will go into detail on the command line, from a batch file, and how it works running it for a logon script.

A. Choose your OS Please….

1. Win9x
To run Kix under Windows 95, 98 you need to have the following files.

kix32.exe
kx95.dll
kx16.dll
kx32.dll

Also you will need the KIXRPC service running for all of the functions to work in Win9x, you can find more about this service in 2.D.1

2. NT
To run KIX under Windows NT, you need the following files.

kix32.exe

B. From a Command line
One of the best ways to run Kix from a command line is to copy the necessary files in to the system path.

For Win9x computers I prefer the "c:\windows\system".
For NT computers the "c:\winnt\system32" is a good location.

Once the proper files are copied to the proper location all you have to do to run KIX is

Kix32 script.kix

By default Kix automatically looks for the following file extensions .kix and .scr, so typing

Kix32 script

will work as long as the script is in the local directory.

C. From a Batch File.
Running kix from a batch file is the most preferred way of running a login script.

A typical login.bat file might look like this

--------start--------
%0\..\kix32 %0\..\logon.kix
-------- end --------


1. Advanced Logon.bat

The following batch file is what the author uses to run his login.kix script. It copies the necessary kix32.exe and related DLL's (depending on OS) to the proper system directory. This not only places the kix32.exe in the path, but increases the run time of the logon script for slow wan connections.

::--------start AdvancedLogon.bat--------
@Echo Off

CLS
ECHO Verifying / Updating Script Software Installation, Please Wait...

IF "%OS%" == "Windows_NT" GOTO WinNT

c:\windows\command\XCOPY %0\..\KIX32.EXE %WINDIR%\SYSTEM\ /D /H /I /R /V > NUL
c:\windows\command\XCOPY %0\..\KX16.DLL %WINDIR%\SYSTEM\ /D /H /I /R /V > NUL
c:\windows\command\XCOPY %0\..\KX32.DLL %WINDIR%\SYSTEM\ /D /H /I /R /V > NUL
c:\windows\command\XCOPY %0\..\KX95.DLL %WINDIR%\SYSTEM\ /D /H /I /R /V > NUL
ECHO Loading Logon Script, Please Wait...
%WINDIR%\SYSTEM\KIX32.EXE %0\..\logon.kix
GOTO End

:WinNT
XCOPY %0\..\KIX32.EXE %WINDIR%\SYSTEM32\ /D /H /I /R /V > NUL
ECHO Loading Logon Script, Please Wait...
%WINDIR%\SYSTEM32\KIX32.EXE %0\..\logon.KIX
GOTO end

:End

::-------- end AdvancedLogon.bat--------

D. The NETLOGON folder

In order for a logon script to work the client will make a connection to a Domain Controllers \\server\netlogon share. You will keep all of your Kix EXE and DLL's in this folder.

1. The KIXRPC Service.

In order to use some of the more advanced macro features in a win9x environment, you will need the Kixrpc service running on the domain controller that the user is currently logging in to.

The Kix Manual has excellent instructions on how to install this service on to your Domain Controllers.

2. How to get all your Domain Controller's in a row.

In order for a person to logon to your network they will first make a connection to either a PDC or a BDC (Domain Controllers).

Since the possibility exists for user A to logon using the PDC while user B is logging using the BDC, you must have the current logon script on ALL Domain controllers.


a. The Microsoft way.

You can use Directory replication to push out the same logon script from the PDC to all BDC's. This is the preferred method for a LARGE domain and is really beyond the scope of this document. You can find more on this in MS knowledge base article #Q101602

b. Just copy it by hand.

Now if your number of Domain Controllers is small (I will leave it up to the reader to define what small is), you can just copy the current logon script to all domain controllers by hand.

Here is a Kix script that I use to do this for me.

;--------start repl.kix--------
break on cls

;-----------------------------------------------------------------------------
; login script replication to all domain controllers
;
; Please create a file "controllers.txt" and place it in the same directory
; as this script. the contents of "Controllers.txt" should be like the
; following
;
; \\server1
; \\server2
; \\server3
; \\server4
;
; Each server is a Domain Controller
;
; You can share the "%systemroot%\system32\repl\import\scripts" on each domain
; controller and change $target to point to that share if one or more of your
; Domain controllers are not using the WINNT directory, or if not installed
; to the c:
;
; You will also need the program xnet.exe in the current directory. It came
; with the kix32 program.
;-----------------------------------------------------------------------------

$file = "Controllers.txt"
$logonscript = "logon.kix"
$logonbat = "logon.bat"
$target = "\c$\winnt\system32\repl\import\scripts"

;-----------------------------------------------------------------------------
;         DO NOT EDIT BELOW THIS LINE
;-----------------------------------------------------------------------------

$q = open(1,$file)
if @error <> 0
   ? "List of servers was not found!!"
   ? "PROGRAM ENDING"
   ?
   ? @serror + ' "$file"'
   exit
endif

gosub Kix_UpGrade

$server = readline(1)
while @error = 0
   ? "============================================================================"
   ? "Copying $logonscript & $logonbat to $server$target"

   copy $logonscript $server + $target
   if @error <> 0
      ? "There was an error copying $logonscript to $server$target"
      ? @serror
   else
      ? "   $logonscript copied OK"
   endif

   copy $logonbat $server + $target
   if @error <> 0
      ? "There was an error copying $logonbat to $server$target"
      ? @serror
   else
      ? "   $logonbat copied OK"
   endif

   if $upgrade = "yes"
      ?
      ? "Upgrading Kix32 on $server$target"
      copy "kix32.exe" $server + $target
         if @error <> 0
            ? "   There was an error copying KIX32.EXE to $server$target"
            ? "   @serror"
         else
            ? "   kix32.exe copied OK"
         endif
      copy "kx*.dll" $server + $target
         if @error <> 0
            ? "   There was an error copying kx*.dll to $server$target"
            ? "   @serror"
         else
            ? "   ki*.dll copied OK"
         endif
      ? "   Stoping the kxrpc service on $server"
      shell "%comspec% /c xnet stop $server\kxrpc > nul"
      copy "kxrpc.exe" $server + $target
         if @error <> 0
            ? "   There was an error copying kxrpc.exe to $server$target"
            ? "   @serror"
         else
            ? "   kxrpc.exe copied OK"
         endif
      ? "   Starting the kxrpc service on $server"
      shell "%comspec% /c xnet start $server\kxrpc > nul"
   endif
   $server = readline(1)
loop
exit

;----------------------------
   :Kix_UpGrade
;----------------------------

:wrong
? "Would you like to update Kix32 at this time? (y/n)"
get $yn
select
   case lcase($yn) = "y"
      $upgrade = "yes"
   case lcase($yn) = "n"
      $upgrade = "no"
   case 1
      goto wrong
endselect
return
;-------- end repl.kix[/code]


3. Basic SYNTAX

SYNTAX is very important when it comes to writing your Kix script. I personally have (almost) pulled hair out trying to get a program to work, just to find the I left a " out from the 3rd line of a 30 line script. But if you follow these simple rules you should be ok.

Rule 1

If the command you are typing requires an ending argument go ahead and type it in right after you type the command

Example: shell " " Then just come back in fill in what you are shelling to.
Example: substr( )
Example:    if $x = $y
         ;code goes here
      endinf

the 3rd example is very important! If you are going to use an IF … THEN routine go ahead and type the ENDIF on the next line, and just go back and fill in the rest of the code. Doing it this way you will have less of a chance of forgetting the all important closing argument!

Rule 2

Use tabs and spaces, to bring some order to your code. Since Kix32 is a free-format language, tabs and spaces will not bother how your code performs. Lets take the above IF .. THEN statement as an example.

IF $x = $y
   ? "hey guess what! X = Y"
   ? "I bet that you didn't know that….."
ENDIF

By preceding everything inside the IF … THEN statement with a tab, we can tell just by glancing at the code that the two print line lines are inside the IF … THEN.

Rule 3

The comment is your friend! Don't be afraid to use ; in your code.

IF $x = $y   ;checking to see if $x and $y are the same if they are do nothing, if not……
   ;they are the same, do nothing
ELSE
   ? "Look's like X and Y are not the same"
ENDIF

The more that you can write down that documents your train of thought (or lack of) the easier it is to spot simple logic mistakes.

A. IF … THEN / SELECT CASE

Using IF .. THEN and SELECT CASE are excellent ways to write logic gates into your code. You have already seen some basic examples of the IF … THEN statement, let go in to more detail.

IF … THEN

When you are doing a IF statement in Kix32 you are really doing a simple test of 1 variable against another.

Example 1:
IF $a = 1
"$$a = 1"
ENDIF

In Example 1, you are testing to see if $a = 1, if this is found to be true then it will print out "$a = 1"

(the use of double $$ is necessary, otherwise Kix32 will want to print the value of $a and not "$a". This is same for @ and % )

Many times you will be testing the return code of another command, one of the more common occurrences of this is the ingroup() command.

Example 2:
IF INGROUP("Domain Users") = 1
   ? "this person is in the Domain Users group"
ENDIF
IF INGROUP("Domain Admins") = 1
   ? "this person is in the Domain Admins group"
ENDIF

(It has been my experience that domain groups are case sensitive)

In this Example, we are testing to see what the return code for ingroup() will be. To get a better understanding of what I mean run the following.

;--------Start IF_ingroup.kix--------
BREAK ON CLS

$Return_Code = INGROUP("Domain Users")
? 'The return code for "INGROUP("Domain Users")" is "$Return_Code"'
;-------- end IF_ingroup.kix--------

If everything went ok, and you are a member of the Domain Users group the return code would = 1.

You can clearly see that the IF… statement works by comparing 2 variables against each other, if the outcome is true then Kix will run the next set of commands until an ENDIF is reached.

You can also tell an IF… statement to do something if the outcome is false by using the ELSE command.

;--------Start IF_ELSE.kix--------
$a = "thing1"
$b = "thing2"
IF $a = $b
   ? "$$a = $$b"      ;if $a = $b is true then this line will be executed
ELSE
   ? "$$a doesn't = $$b"   ;if $a = $b is false then this line will be executed
ENDIF
;-------- end IF_ELSE.kix--------

Let take this one step further. Since we are comparing two variables against each other and checking to see if the outcome is false or true, you can use any operator, you have all ready seen the =, but you may use any of the following.

<    Less than
>   Greater Than
=   Equal
<>   NOT Equal
<=   Less then or Equal to
>=   Greater then or Equal to
AND   
OR   

Here are a few examples

1.   If $a > $b
;$a is greater than $b
endif

2.   IF $a <> $b
; $a doesn't = $b
ENDIF

3.   IF $a = $b AND $c = $d
;this is only true if $a equals $b AND $c equals $d
ENDIF

SELECT … CASE

Just like IF … THEN you can use SELECT … CASE to form logic gates inside your script.

Unlike IF … THEN once a CASE is found to be true inside a SELECT … CASE, all other CASE's are ignored in the current select case.

EXAMPLE:

SELECT
   CASE $a = 1
      ? "hey look at that $$a = 1"
   CASE $a = 2
      ? "hey look at that $$a = 2"
   CASE $a = 1
      ; $a = 1 here too, but since this case is all ready
; been true at the very first case, you will never see this case come true.
         CASE 1
            ;by placing "CASE 1" at the end of a SELECT … CASE this means that since
;all other CASE's were false this one will be true.
ENDSELECT

That makes SELECT … CASE very good for a situation where you have 1 single variable that may have several possible values to it, but you only want it to react to a certain value and once one is found ignore all others.

EXAMPLE:

;--------Start select.kix--------
$test = 1

SELECT
   Case $test = 1
      $test = 2
   Case $test = 2
      $test = 1
ENDSELECT

? $test
;-------- end select.kix--------

what does $test equal at the end of this script? If you say 2, you are correct

lets walk through this script

Line 1 $test = 1 we set the variable $test to = 1

Lines 3 - 8. then call a SELECT … CASE.

The very first CASE (line 4) is true so we then set $test to equal 2

Remember since this is a SELECT … CASE once we have found a CASE that is true we ignore all other CASE's. So having reset $test to equal 2 we then end the SELECT … CASE so the 2nd case on line 6 never has a chance to be true..

As in the IF …THEN statement you can use the following operators to prove a CASE true.

<    Less than
>   Greater Than
=   Equal
<>   NOT Equal
<=   Less then or Equal to
>=   Greater then or Equal to
AND   
OR   

B. Nested SYNTAX

Nested means that you are calling another IF .. THEN / SELECT … CASE from inside a IF .. THEN / SELECT … CASE.

Are you confused yet [Smile] !!!

You can nest IF .. THEN / SELECT … CASE as deep as you want, or until your mind screams NO MORE!!! lets do a few Examples.

EXAMPLE 1:
$test1 = 1
$test2 = 2
IF $test1 = 1
   IF $test2 = 2
      ? "this line will only print if $$test1 = 1 and then $$test2 = 2"
   ELSE
      ? You were close! $$test1 = 1, but $$test2 doesn't = 2"
   ENDIF
ELSE
   ? "$$test1 doesn't even equal 1 so we were never even able to test to see what $$test2 equaled."
ENDIF

You can even mix and match IF … THEN with SELECT … CASE. The following Example is one that I find useful.

;--------Start drive_mapping.kix--------
SELECT
   CASE @INWIN = ("1") ;Windows NT
      IF INGROUP("Domain Admins") = 1
         USE x: "\\server\NT_admin"
      ENDIF
      IF INGROUP("Domain Users") = 1
         USE y: "\\server\NT_users"
      ENDIF
   CASE @INWIN = ("2") ;Windows 9x
      IF INGROUP("Domain Admins") = 1
         USE x: "\\server\Windows_admin"
      ENDIF
      IF INGROUP("Domain Users") = 1
         USE y: "\\server\Windows_users"
      ENDIF
ENDSELECT
;-------- end drive_mapping.kix--------

Drive_Mapping.kix uses a select case to decide if the user is on a NT computer or a Win9x computer. Once the proper CASE has been proven true I then use IF… statements to check if they are in groups. If a IF… statement is proven true, they then get drive's mapped based on the group that they are in.

So not only they get different drive mappings based on what groups they are a member of, but also different drive mappings based on what type of computer that they are logging from.

C. $Variables (Integers & Strings)

Using $variables in KIX is as inevitable as the sun setting at the end of the day. You have already see several variables in use, but lets dig a little deeper and shed some light of some of the more trickier spots of using a variable in KIX.

First off lets define the type of variables that KIX can use.

Variables That Kix can use are (as of 3.62. this might change with future versions)
a.   Integers
b.   Strings.

Sounds straight forward, but this can throw some people for a loop.

Integers
First off an integer is a number like 1, 24, 1000, 27. You get the idea.

KIX can not work with decimals!! Any attempt to use a decimal will just result in Kix using the integer value of the number. A way to get around this is to drop the decimal and treat the whole thing as an integer, and put the decimal back in when you are done.

To set a variable to equal an interger your code would look something like this.

$a = 27

Notice that the "" are missing. This is to let kix know that the value of $a is an integer and not a string . This is very important so that Kix knows the difference.

;--------Start Interger.kix--------
break on cls
? "this Program will start in 3 seconds"
? 'Press "Ctrl+C" to stop this program'
sleep 3

$a = 1      ;notice no ""

:bigloop
$a = $a + 1
? $a
goto bigloop

;-------- end Interger.kix--------

After running the above script you will see Kix count from 1 to 2146438647 (if you didn't press CTRL+C to exit the program)

Now lets run this one….


--------Start NonInterger.kix--------
code:
break on cls

$a = "1" ;notice the ""

while len("$a"); < 100
$a = $a + 1
? $a
loop

-------- end NonInterger.kix--------

In this script we set $a to equal "1" notice that this was a string and not an integer, and we got very different results!

1
11
111
1111
11111


When doing math calculations with Kix it is very important to make sure that the variable you are working with is an integer and not a string. This is where the val() command comes in to play.

$a = "1"
$a = val("$a")

in the first line we set $a to equal the string "1"
the second line we then reset $a to equal the integer value of $a
(as a side note this may seem a little confusing at first, but keep in mind that when we are run the 2nd line $a still equals the string "1". After the 2nd line has run then $a will equal the integer value of 1)

as you can see the use of val() is a great way to make sure that you are working with an integer and not a string. One of the places that you would use this is in something like the following.

;--------Start AddInteger.kix--------
break on cls

? "Please inter a number between 1 - 5"
get $choice

$number = val("$choice")

Select
   case $number = 1
      ? "You Picked 1"
      $add = $number + 10
      ? "$number + 10 = $add"
   case $number = 2
      ? "You Picked 2"
      $add = $number + 10
      ? "$number + 10 = $add"
   case $number = 3
      ? "You Picked 3"
      $add = $number + 10
      ? "$number + 10 = $add"
   case $number = 4
      ? "You Picked 4"
      $add = $number + 10
      ? "$number + 10 = $add"
   case $number = 5
      ? "You Picked 5"
      $add = $number + 10
      ? "$number + 10 = $add"
   case 1
      ? "I am sorry that is not a number between 1 and 5!"
endselect
;-------- end AddInteger.kix--------

As you can see it is very important to pay close attention when working with integers in Kix.

Strings

Ok we have gone over what an integer-variable is, now let go over what a string-variable is.

1. A string-variable is anything that is in quotes.

That’s it, that’s the big secret!!

$a = "String" This is a string-variable.
$b = 27 This is an integer-variable.

And to convert a Integer-Variable into a String-Variable just place it in quotes.

$a = 27
$string = "$a"

the variable $string now equals "27".


4. MACROS

Kix comes with several built in macros that contain some extremely helpful information.
(the following was taken from the Kix manual)

Macro   Definition
ADDRESS      Address of the network adapter
COMMENT      User comment
CURDIR      Current directory
DATE      Date (in the format YYYY/MM/DD)
DAY      Day of the week (Monday, Tuesday, and so on)
DOMAIN      Domain or workgroup the computer belongs to
DOS      Version of Windowsnbsp;NT
ERROR      Return code of the most recent command or function. A return
      code of 0 means the command or function was successful. Any other value
      indicates an error.
FULLNAME   Full name of current user
HOMEDIR      Short name of the directory part of home directory
HOMEDRIVE*   Drive letter of drive containing home directory
HOMESHR      Server and share name part of home directory
HOSTNAME   Fully qualified TCP/IP host name (including TCP/IP domain name)
INWIN      Operating system: 1nbsp;=nbsp;Windowsnbsp;NT; 2nbsp;=nbsp;Windowsnbsp;9x
IPADDRESSx   TCP/IP address (possible values for x are 0 - 3#41.
      [b]Note[/b]Addresses are padded so that the resulting string always
      consists of four sets of three characters separated by periods. For
      example, if your IP address is 123.45.6.7, @IPADDRESS0 is 123. 45. 6. 7.
KIX      Version of KiXtart
LANROOT      Directory where network software resides (usually Systemroot\System32)
LDOMAIN*   Logon domain
LDRIVE      Drive that is redirected to \\logonserver\NETLOGON
LM      Version of network software
LONGHOMEDIR   Long name of the directory part of home directory
LSERVER      Logon server
MAXPWAGE   Maximum password age
MDAYNO      Day of the month (1-31)
MONTHNO      Months since January (1-12)
MONTH      Name of the month
PRIMARYGROUP*   urrent user's primary group
PRIV      User's privilege level (GUEST, USER, ADMIN)
PWAGE      Password age
RAS      Number of active Remote Access Service (RAS) connections
RSERVER*   KXRPC server used for the current session
SCRIPTDIR   Directory of current script
SERROR      Error text corresponding with @ERROR
SID*      Current user's Windowsamp;nbsp;NT Security Identifier (SID)
SITE**      Name of the site in which the system resides
STARTDIR   Directory from which KiXtart was started
SYSLANG      Full English name of the language of the operating system
      specified in the format defined by ISO
      Standard 639. (example : "0413Dutch (Standard)").
TIME      Current time (in the format HH:MM:SS)
USERID      Current user's Windowsnbsp;NT user ID
USERLANG   Full English name of the language selected by the current
      user specified in the format defined by
      ISO Standard 639. (example : "0413Dutch (Standard)").
WDAYNO      Days since Sunday (1 – 7)
WKSTA      Computer name
WUSERID      Current user's Windows user ID
YDAYNO      Days since January 1 (1 – 365)
YEAR      Current year

*Available on computers running Windows 9x only if the KiXtart RPC service is running.
** Only available on clients with full Active Directory support.

To use a macro in your code you would precede the macro name with a @.
For example

? @fullname
? @userid

Would print out the contents of the Full Name fields in user manager on the first line, and on the next line would be the users logon id.

[ 28. July 2003, 08:27: Message edited by: kdyer ]
_________________________
Utilize these resources:
UDFs (Full List)
KiXtart FAQ & How to's