Summary
This is a lot of custom scripting, mostly AutoIT being used in the K2000 appliance to create a new feature not currently available to the K2000, choosing your post install tasks you wish to use when you kick off an image in real time instead of having to log into the web interface and drag/drop your tasks.

The main reason to want this is you have an environment with lots of smaller tasks or applications that can vary a lot from one deployment to the next and its too much trouble to log in and change for each deployment (Think perhaps multiple versions of Java as an example).  It is also  helpful in a multi user environment where more than one tech may use the appliance for the same image and make changes to the tasks before you start a deployment and you end up deploying the wrong tasks.

I would say this is not ideal if you just have 2 or 3 different baseline setups that are always the same and do not change very much.  For that you can just use the duplicate image feature to create a copy of your image, and then permanently assign tasks to that duplicate (Duplicate images do not take up additional space on the K2000)

Last, this is for you if you just want to learn some really cool scripting, concepts and techniques aka, You are a nerd...like me.


How it Works (High Level Overview)
We have essentially a 3 part process to this.
A GUI that we setup as a Pre-Install Task so that right away we get the ability to click on the Post-Install Tasks we want to deploy.

The GUI will take your selections and leave some "breadcrumbs" behind so that we can later look for them.  In this case, we will be creating an .INI file and leaving it at the root of the C: right after we have created our partitions.

CHKgNb.jpeg
njVqj5.jpeg

The rest of the imaging process will proceed as per normal until we reach our Post-Install Tasks section.
At this point, our first Post-Install task is the Interpreter.  This is just a middle man script that will go find our Breadcrumbs (Our .INI File) read what we chose to install from the GUI and write those sections to the Registry.

The rest of the magic happens with the actual Post Install Tasks themselves.

Rather than write each and every job to look for our registry entries, we have a Job Interpreter script that runs along with each Kustom Task.  This way we can use the same jobs we would use as a normal post install task, or stand alone automated installations.  The Job interpreter's "job" is to read the job#, check the registry to see if it should execute the attached install and if it finds it, then proceed, else mark the current task as complete and continue with deployment without actually installing anything.

pjkQ7A.jpeg

Implementation - Part 1 The GUI and Pre-Install Task Phase

Since not everybody uses AutoIT and can compile there own .exe I have written these tasks to be super dynamic and easily changed by each user via .INI files.
So you can use the same .EXE without touching it, and just modify the .INI file to modify the jobs you want to present.

Note: I can not attach files to a blog post so I will try to provide a download link to get the pre-compiled scripts later for now source code will be posted inside this post.

Of course I will include the source code as well so you can see how it was done, and modify the source code should you need to.

Insight: Our Pre-Install tasks takes place in the PBE (Pre Boot Environment) this can be 32bit or 64bit depending on your setup.  The PBE will not run a pre-compiled EXE that does not match the same environment.

We will compile the GUI twice once as a x64 binary and once as a x86 binary so it can be run from both types of PBE.
Instead of running two different tasks.  I like to keep things clean.  So the first task is going to be a small BAT script that checks the environment and launches the appropriate GUI binary.

Here is how the job looks in the K2000
qkeuMU.jpeg

Here is the files contained in our .ZIP
The .BAT file, our x86 GUI, our x64 GUI and the GUI's configuration INI file.
Hqnuhw.jpeg

This is how I made the .BAT file

____ Determin6432bit.bat ____
wmic os get osarchitecture | find "64-bit"
IF %ERRORLEVEL% == 0 goto 64bit
IF %ERRORLEVEL% == 1 goto 32bit

goto END

:64bit
"Choose(PreInstall-Localx64).exe"
goto END

:32bit
"Choose(PreInstall-Localx86).exe"
goto END

:END
___________________________________

Now here is the source code for the GUI itself so you can see how that works, and compile it yourself using AutoIT if you would like.

___ Choose.exe ____

#RequireAdmin
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <File.au3>

Global $fINI = @ScriptDir & "\Choose.ini"

If NOT FileExists($fINI) Then ;Exit the GUI with message if the INI file is missing
MsgBox(0, "Notice", "Critical Error, Missing Choose.ini File Exiting Application")
Exit 1
EndIf

$aNames = IniReadSection($fINI, "JobName")
$aIsChecked = IniReadSection($fINI, "IsChecked")
$aIsEnabled = IniReadSection($fINI, "IsEnabled")
$iGUITimeOut = IniRead($fINI, "Extra", "GUITimeOut", "4")
$sMachineMac = ""

AdlibRegister("_SaveSelections", 1000*60*$iGUITimeOut) ;1000 milisecond * 60 = 1 Minute (Will exit the GUI without user interaction after X Time)

FileDelete("C:\KustomPostInstalls.ini") ;Delete INI file just incase it already exists so we do not append old selections.

$K2000 = GUICreate("K2000 Dynamic Task Installer", 615, 437, 192, 124, -1, BitOR($WS_EX_TOPMOST,$WS_EX_WINDOWEDGE))
$Label1 = GUICtrlCreateLabel("K2000 Dynamic Task Installer", 176, 8, 241, 24)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
$Checkbox1 = GUICtrlCreateCheckbox("Checkbox1", 32, 48, 225, 17)
$Checkbox2 = GUICtrlCreateCheckbox("Checkbox2", 32, 80, 225, 17)
$Checkbox3 = GUICtrlCreateCheckbox("Checkbox3", 32, 112, 225, 17)
$Checkbox4 = GUICtrlCreateCheckbox("Checkbox4", 32, 144, 225, 17)
$Checkbox5 = GUICtrlCreateCheckbox("Checkbox5", 32, 176, 225, 17)
$Checkbox6 = GUICtrlCreateCheckbox("Checkbox6", 32, 208, 225, 17)
$Checkbox7 = GUICtrlCreateCheckbox("Checkbox7", 32, 240, 225, 17)
$Checkbox8 = GUICtrlCreateCheckbox("Checkbox8", 32, 272, 225, 17)
$Checkbox9 = GUICtrlCreateCheckbox("Checkbox9", 32, 304, 225, 17)
$Checkbox10 = GUICtrlCreateCheckbox("Checkbox10", 32, 336, 225, 17)
$Checkbox11 = GUICtrlCreateCheckbox("Checkbox11", 312, 48, 225, 17)
$Checkbox12 = GUICtrlCreateCheckbox("Checkbox12", 312, 80, 225, 17)
$Checkbox13 = GUICtrlCreateCheckbox("Checkbox13", 312, 112, 225, 17)
$Checkbox14 = GUICtrlCreateCheckbox("Checkbox14", 312, 144, 225, 17)
$Checkbox15 = GUICtrlCreateCheckbox("Checkbox15", 312, 176, 225, 17)
$Checkbox16 = GUICtrlCreateCheckbox("Checkbox16", 312, 208, 225, 17)
$Checkbox17 = GUICtrlCreateCheckbox("Checkbox17", 312, 240, 225, 17)
$Checkbox18 = GUICtrlCreateCheckbox("Checkbox18", 312, 272, 225, 17)
$Checkbox19 = GUICtrlCreateCheckbox("Checkbox19", 312, 304, 225, 17)
$Checkbox20 = GUICtrlCreateCheckbox("Checkbox20", 312, 336, 225, 17)
$Button1 = GUICtrlCreateButton("Proceed", 128, 384, 345, 33)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
GUISetState(@SW_SHOW)

For $i = 1 to $aIsChecked[0][0] ;Read the INI file and check any boxes set to be checked by default.
GUICtrlSetState(Eval("Checkbox" & $i), $aIsChecked[$i][1])
Next

For $i = 1 to $aNames[0][0] ;Read the INI file and give each task its name
GUICtrlSetData(Eval("Checkbox" & $i), $aNames[$i][1])
Next

For $i = 1 to $aIsEnabled[0][0] ;Read the INI file and hide any tasks set to be hidden for OCD people
If $aIsEnabled[$i][1] = 0 Then GUICtrlSetState(Eval("Checkbox" & $i), $GUI_HIDE)
Next

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
ExitLoop
EndSwitch
WEnd

_SaveSelections()

Func _SaveSelections() ;Take our selections and save them to a INI file at the root of the C:
For $i = 1 to $aIsChecked[0][0]
If GuiCtrlRead(Eval("Checkbox" & $i)) = 1 Then IniWrite("C:\KustomPostInstalls.ini", "PostInstallTasks", "Job" & $i, "1")
Next
Exit
EndFunc ;_SaveSelections()

___________________

Here is the .INI file that goes with the GUI so that you can configure its options.

____ Choose.ini _____
[JobName]
;Use String Value For Name
Job1=Install Java8u121
Job2=Install HealthEMS 4.11.27204 Desktop
Job3=Install Cisco AnyConnect 4.3.05017
Job4=Install Barracuda WSA 4.4.5.40
Job5=Install Prolific GPS Puck Driver v118
Job6=Activate Windows
Job7=Activate Office
Job8=Job8
Job9=Job9
Job10=Job10
Job11=Job11
Job12=Job12
Job13=Job13
Job14=Job14
Job15=Job15
Job16=Job16
Job17=Job17
Job18=Job18
Job19=Job19
Job20=Job20
[IsChecked]
;0 Disabled Not Checked By Default | 1 Enabled Checked By Default
Job1=0
Job2=0
Job3=0
Job4=0
Job5=0
Job6=1
Job7=1
Job8=0
Job9=0
Job10=0
Job11=0
Job12=0
Job13=0
Job14=0
Job15=0
Job16=0
Job17=0
Job18=0
Job19=0
Job20=0
[IsEnabled]
;0 Disabled Option Will Not Show on GUI | 1 Enabled Option Will Be Displayed on GUI
Job1=1
Job2=1
Job3=1
Job4=1
Job5=1
Job6=1
Job7=1
Job8=1
Job9=1
Job10=1
Job11=1
Job12=1
Job13=1
Job14=1
Job15=1
Job16=1
Job17=1
Job18=1
Job19=1
Job20=1
[Extra]
;GUI Time Out in Minutes for GUI to close without user input and apply selections
GUITimeOut=4
_______


Implementation - Part 2 The Post-Install Task Interpreter

At this point, we have deployed an image and just hit the Post-Install Phase, our first task should be setup as our Interpreter.

Here is how the task is setup in the K2000
y7b6P2.jpeg

Since we are now out of the PBE and in our Windows environment, we no longer have to have a separate binary for 32bit and 64bit.  We can use a 32bit binary for both Windows environments.  So we just have our 32bit EXE being called as our first Post Install Task.

The interpreter finds the .INI file we created with the GUI earlier, reads the selections and saves it to the Windows Registry.

Here is the source code for the Interpreter, I called it INItoReg.

___ INItoREG.exe ___
#RequireAdmin
#include <File.au3>
#include <Array.au3>

$aINI = INIReadSection("C:\KustomPostInstalls.ini", "PostInstallTasks") ;Read our INI File
;_ArrayDisplay($aINI)

If NOT IsArray($aINI) Then EXIT ;If it has no options or is missing Exit

For $i = 1 to $aINI[0][0] ;Save all the INI entries to their own Registry Key
RegWrite("HKLM\SOFTWARE\K2000\KustomPostInstall", $aINI[$i][0], "REG_SZ", $aINI[$i][1])
Next
________________


Implementation - Part 3 Our Kustom Post-Install Tasks

At this point, we have run the GUI as a Pre-Install Task, the Interpreter has run as the first Post-Install Task and we are reaching our actual Jobs that we have set as a Post-Install Task.

So your jobs get to stay exactly the way they are now.  This was designed in a way that you have just one piece of code between the K2000 and your normal Post Install Task, and that middle code determines if the task gets installed.

Here is an example of one of my Jobs and how you set this up.
The Job Interpreter script was setup just like the GUI, to be extremely flexible and all the configuration is changed via an INI file so you do not ever have to change the code or recompile it.  Just change the .INI file for each job.

The K2000 Kustom Post Install Task
UHU84E.jpeg

The ZIP file for the Job
QHHEP8.jpeg

In here the Install Java.exe is my normal automated installer, the .MSI files are the dependency.  The only thing I added to make this work as a Kustom Job is the JobInterpreter.exe and its JobInfo.ini file.

Here is the source code for the JobInterpreter.exe

___ JobInterpreter.exe ___
#RequireAdmin
$fINI = @ScriptDir & "\JobInfo.ini"
If NOT FileExists($fINI) Then
MsgBox(0, "", "Critical Error - Missing .INI file JobInfo.ini")
Exit
EndIf


$sJobNumber = IniRead($fINI, "JobInfo", "JobNumber", "")
$sJobBinary = IniRead($fINI, "JobInfo", "JobBinary", "")
$sJobName = IniRead($fINI, "JobInfo", "JobName", "")
$sJobWaitComplete = IniRead($fINI, "JobInfo", "JobWaitComplete", "0")
If NOT RegREad("HKLM\SOFTWARE\K2000\KustomPostInstall\", "Job" & $sJobNumber) = 1 Then Exit
MsgBox(0, "", "Currently Launching Job# " & $sJobNumber & " " & $sJobName, 2)
ShellExecute(@ScriptDir & "\" & $sJobBinary)

While ProcessExists($sJobBinary)
Sleep(10)
WEnd

If StringInStr($sJobBinary, ".bat") Then
While ProcessExists("cmd.exe")
Sleep(10)
WEnd
EndIf

Sleep($sJobWaitComplete * 1000)
________

The INI file  handles all the specifics for the job.  What binary to run for the task, what registry key we are looking for, etc.
Here is the source code for JobInfo.ini

___ JobInfo.ini ___
[JobInfo]
;Job Number Must Be Exclusive
JobNumber=1
;Job Name Just used for reference
JobName=Java8u121
;Job Binary is the single file to be executed for install
JobBinary=Install Java8u121.exe
;Job Wait is extra time added at end for a install to complete in seconds i.e. 5 = 5 Seconds
JobWaitComplete=0
_____________

The tricky thing here that I had to figure out is that the K2000 executes your job directly usually, and it waits for completion of that task before it moves to the next.
If your instead calling a middle script like this.  The K2000 moves to the next task soon as JobInterpreter.exe completes!

So that is why the code now has its own internal wait function so it will keep JobInterpreter.exe open until the install process it is calling is completed. 
It works perfectly with a .EXE (most of my installs are self written .EXE) but I found if its a .BAT file that it actually calls the CMD.exe process so that is why I also added an extra line to check for the .BAT extension and wait for CMD to finish installing your job.

It should work for pretty much everything, but if you find some kind of job that it does not work for, just call it from a .BAT file and that should solve it.

Example: My install Cisco AnyConnect job installs to .MSI files so I just created the Kustom Post Install Task to look like this.

tDPEr7.jpeg
ZowoQQ.jpeg
td1gAg.jpeg
ubefNc.jpeg




Nerdy Extras

I will try to post here a download link for all the actual .au3 files (The AutoIt Source Code) the pre-compiled .exe files, the .ini files etc.
Also this was built by me one step at a time, before it evolved into what you see above it had other phases.

For those with a different environment, you may find some of these off shoots useful.

Pre-Install Task GUI Network Version
Before I found I could save the .INI file to the root of the C: to carry my breadcrumbs from the PBE to the Windows Environment I found that the K2000 has a hidden temp folder that I could send the .INI file to.

So this is the source code for the Network GUI that save the INI to the K2000 PETemp folder, and since we are now using a shared location instead of a local location I had to worry about the file names.  Each computer needed to have a unique file name and find its own INI file in the Post phase.  For that I used the MAC address.

__ Choose.exe Network Version ___
#RequireAdmin
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <File.au3>

Global $fINI = @ScriptDir & "\Choose.ini"

If NOT FileExists($fINI) Then
MsgBox(0, "Notice", "Critical Error, Missing Choose.ini File Exiting Application")
Exit 1
EndIf

$aNames = IniReadSection($fINI, "JobName")
$aIsChecked = IniReadSection($fINI, "IsChecked")
$aIsEnabled = IniReadSection($fINI, "IsEnabled")
$iGUITimeOut = IniRead($fINI, "Extra", "GUITimeOut", "4")
$sMachineMac = ""

AdlibRegister("_SaveSelections", 1000*60*$iGUITimeOut) ;1000 milisecond * 60 = 1 Minute

$objWMIService  = ObjGet("winmgmts:{impersonationLevel=impersonate}")
$netAdapterSet = $objWMIService.ExecQuery("select * from Win32_NetworkAdapter where DeviceID = 0")
For $netAdapter in $netAdapterSet
    $sMachineMac = $netAdapter.MACAddress
Next

$sMachineMAC = StringReplace($sMachineMAC, ":", "")

#Region ### START Koda GUI section ### Form=C:\Users\it022565\Desktop\K2000 Custom Jobs\K2000.kxf
$K2000 = GUICreate("K2000 Dynamic Task Installer", 615, 437, 192, 124, -1, BitOR($WS_EX_TOPMOST,$WS_EX_WINDOWEDGE))
$Label1 = GUICtrlCreateLabel("K2000 Dynamic Task Installer", 176, 8, 241, 24)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
$Checkbox1 = GUICtrlCreateCheckbox("Checkbox1", 32, 48, 225, 17)
$Checkbox2 = GUICtrlCreateCheckbox("Checkbox2", 32, 80, 225, 17)
$Checkbox3 = GUICtrlCreateCheckbox("Checkbox3", 32, 112, 225, 17)
$Checkbox4 = GUICtrlCreateCheckbox("Checkbox4", 32, 144, 225, 17)
$Checkbox5 = GUICtrlCreateCheckbox("Checkbox5", 32, 176, 225, 17)
$Checkbox6 = GUICtrlCreateCheckbox("Checkbox6", 32, 208, 225, 17)
$Checkbox7 = GUICtrlCreateCheckbox("Checkbox7", 32, 240, 225, 17)
$Checkbox8 = GUICtrlCreateCheckbox("Checkbox8", 32, 272, 225, 17)
$Checkbox9 = GUICtrlCreateCheckbox("Checkbox9", 32, 304, 225, 17)
$Checkbox10 = GUICtrlCreateCheckbox("Checkbox10", 32, 336, 225, 17)
$Checkbox11 = GUICtrlCreateCheckbox("Checkbox11", 312, 48, 225, 17)
$Checkbox12 = GUICtrlCreateCheckbox("Checkbox12", 312, 80, 225, 17)
$Checkbox13 = GUICtrlCreateCheckbox("Checkbox13", 312, 112, 225, 17)
$Checkbox14 = GUICtrlCreateCheckbox("Checkbox14", 312, 144, 225, 17)
$Checkbox15 = GUICtrlCreateCheckbox("Checkbox15", 312, 176, 225, 17)
$Checkbox16 = GUICtrlCreateCheckbox("Checkbox16", 312, 208, 225, 17)
$Checkbox17 = GUICtrlCreateCheckbox("Checkbox17", 312, 240, 225, 17)
$Checkbox18 = GUICtrlCreateCheckbox("Checkbox18", 312, 272, 225, 17)
$Checkbox19 = GUICtrlCreateCheckbox("Checkbox19", 312, 304, 225, 17)
$Checkbox20 = GUICtrlCreateCheckbox("Checkbox20", 312, 336, 225, 17)
$Button1 = GUICtrlCreateButton("Proceed", 128, 384, 345, 33)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

For $i = 1 to $aIsChecked[0][0]
GUICtrlSetState(Eval("Checkbox" & $i), $aIsChecked[$i][1])
Next

For $i = 1 to $aNames[0][0]
GUICtrlSetData(Eval("Checkbox" & $i), $aNames[$i][1])
Next

For $i = 1 to $aIsEnabled[0][0]
If $aIsEnabled[$i][1] = 0 Then GUICtrlSetState(Eval("Checkbox" & $i), $GUI_HIDE)
Next

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
ExitLoop
EndSwitch
WEnd

_SaveSelections()

Func _SaveSelections()
RunWait(@comspec & ' /c net use \\**Your K2000 IP**\petemp /user:**Your User ID** **Your  User Password** /persistent:no', "", @SW_HIDE)
For $i = 1 to $aIsChecked[0][0]
If GuiCtrlRead(Eval("Checkbox" & $i)) = 1 Then IniWrite("\\**Your K2000 IP\PeTemp\" & $sMachineMAC & ".ini", "PostInstallTasks", "Job" & $i, "1")
Next
Exit
EndFunc ;_SaveSelections()
________

Post Install GUI Version
My first version of the GUI wrote directly to the Registry.  It was just the GUI and the Jobs however since the PBE has no access to the Windows Registry for your deployment.  It has to be run as a Post Install task.  I did not like waiting for Post Installs to come up and baby sit the image process, that is why we created the Pre-Install version and created the Interpreter to move the INI file into the Registry.  This is also why the JobInterpreter's read the Registry instead of just reading the .INI file directly.  The original version worked this way and I felt no real reason to change all the code when I like the registry anyways.

___ Choose.exe Post Install Task ___
#RequireAdmin
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>

Global $fINI = @ScriptDir & "\Choose.ini"

If NOT FileExists($fINI) Then
MsgBox(0, "Notice", "Critical Error, Missing Choose.ini File Exiting Application")
Exit 1
EndIf

$aNames = IniReadSection($fINI, "JobName")
$aIsChecked = IniReadSection($fINI, "IsChecked")
$aIsEnabled = IniReadSection($fINI, "IsEnabled")
$iGUITimeOut = IniRead($fINI, "Extra", "GUITimeOut", "4")

AdlibRegister("_SaveSelections", 1000*60*$iGUITimeOut) ;1000 milisecond * 60 = 1 Minute

#Region ### START Koda GUI section ### Form=C:\Users\it022565\Desktop\K2000 Custom Jobs\K2000.kxf
$K2000 = GUICreate("K2000 Dynamic Task Installer", 615, 437, 192, 124, -1, BitOR($WS_EX_TOPMOST,$WS_EX_WINDOWEDGE))
$Label1 = GUICtrlCreateLabel("K2000 Dynamic Task Installer", 176, 8, 241, 24)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
$Checkbox1 = GUICtrlCreateCheckbox("Checkbox1", 32, 48, 225, 17)
$Checkbox2 = GUICtrlCreateCheckbox("Checkbox2", 32, 80, 225, 17)
$Checkbox3 = GUICtrlCreateCheckbox("Checkbox3", 32, 112, 225, 17)
$Checkbox4 = GUICtrlCreateCheckbox("Checkbox4", 32, 144, 225, 17)
$Checkbox5 = GUICtrlCreateCheckbox("Checkbox5", 32, 176, 225, 17)
$Checkbox6 = GUICtrlCreateCheckbox("Checkbox6", 32, 208, 225, 17)
$Checkbox7 = GUICtrlCreateCheckbox("Checkbox7", 32, 240, 225, 17)
$Checkbox8 = GUICtrlCreateCheckbox("Checkbox8", 32, 272, 225, 17)
$Checkbox9 = GUICtrlCreateCheckbox("Checkbox9", 32, 304, 225, 17)
$Checkbox10 = GUICtrlCreateCheckbox("Checkbox10", 32, 336, 225, 17)
$Checkbox11 = GUICtrlCreateCheckbox("Checkbox11", 312, 48, 225, 17)
$Checkbox12 = GUICtrlCreateCheckbox("Checkbox12", 312, 80, 225, 17)
$Checkbox13 = GUICtrlCreateCheckbox("Checkbox13", 312, 112, 225, 17)
$Checkbox14 = GUICtrlCreateCheckbox("Checkbox14", 312, 144, 225, 17)
$Checkbox15 = GUICtrlCreateCheckbox("Checkbox15", 312, 176, 225, 17)
$Checkbox16 = GUICtrlCreateCheckbox("Checkbox16", 312, 208, 225, 17)
$Checkbox17 = GUICtrlCreateCheckbox("Checkbox17", 312, 240, 225, 17)
$Checkbox18 = GUICtrlCreateCheckbox("Checkbox18", 312, 272, 225, 17)
$Checkbox19 = GUICtrlCreateCheckbox("Checkbox19", 312, 304, 225, 17)
$Checkbox20 = GUICtrlCreateCheckbox("Checkbox20", 312, 336, 225, 17)
$Button1 = GUICtrlCreateButton("Proceed", 128, 384, 345, 33)
GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

For $i = 1 to $aIsChecked[0][0]
GUICtrlSetState(Eval("Checkbox" & $i), $aIsChecked[$i][1])
Next

For $i = 1 to $aNames[0][0]
GUICtrlSetData(Eval("Checkbox" & $i), $aNames[$i][1])
Next

For $i = 1 to $aIsEnabled[0][0]
If $aIsEnabled[$i][1] = 0 Then GUICtrlSetState(Eval("Checkbox" & $i), $GUI_HIDE)
Next

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
ExitLoop
EndSwitch
WEnd

_SaveSelections()

Func _SaveSelections()
For $i = 1 to $aIsChecked[0][0]
If GuiCtrlRead(Eval("Checkbox" & $i)) = 1 Then RegWrite("HKLM\SOFTWARE\K2000\KustomPostInstall", "Job" & $i, "REG_SZ", "1")
Next
Exit
EndFunc ;_SaveSelections()

___________

Non AutoIT Users

I just crafted a few short snippits of code to show basic ways to do the same kind of concept with native windows scripting in .bat files
I much prefer AutoIT since I know it well and its very powerfull, but if you do not use it or like it and prefer straight up scripts here is some methods.

An example of how to do the "GUI" with a .bat file.  You just answer Y/N to each install.  Note: This is before I created the .INI method it goes directly to Registry.

__ Native Scripting "GUI" .BAT ___
@Echo Off


set /P job1=Do you want to install Job1 [Y/N]?
if /I "%job1%" EQU "Y" set job1=1
if /I "%job1%" EQU "N" set job1=0

set /P job2=Do you want to install Job2 [Y/N]?
if /I "%job2%" EQU "Y" set job2=1
if /I "%job2%" EQU "N" set job2=0

set /P job3=Do you want to install Job3 [Y/N]?
if /I "%job3%" EQU "Y" set job3=1
if /I "%job3%" EQU "N" set job3=0

set /P job4=Do you want to install Job4 [Y/N]?
if /I "%job4%" EQU "Y" set job4=1
if /I "%job4%" EQU "N" set job4=0
 
REM echo %job1%
REM echo %job2%
REM echo %job3%
REM echo %job4%

if %job1% == 1 reg add HKLM\SOFTWARE\K2000\KustomPostInstall /v Job1 /t REG_SZ /d 1
pause
_________

Native Job Interpreter
Same concept, instead of AutoIT using a .BAT file to check for our registry keys and start the installer.

@Echo Off
for /f "tokens=2*" %%a in ('reg query HKLM\SOFTWARE\K2000\KustomPostInstall /v Job1') do set "var=%%b"
if "%var%"=="1" (echo found 1) else echo did not find
pause

________

And that is that!

Should be enough information, samples, and all the source code so that you can implement this for yourself.
Hope somebody finds the information share useful and I look forward to any comments, ideas, and collaboration that comes from this.