since Maik posted one of his Dee Dee Dee moments (I did not know it either) I figured I would post one of my own.
I have a mini lab setup on my Laptop using MS Virtual Server. virtual server has two types of networks, virtual and external. It will not bind to a wireless adapter, so to be able to connect to my virtual machines I was plugging into my linksys router using a cat5e cable. I went to give a demo today at work and was dragging out my Linksys so I could get the “network” up and one of the guys asked “Why aren’t you using the loopback adapter”.
Well, I did not know about it. Now my network is hooked up sans Linksys and cables.
previous posts in this series:
- microsoft deployment toolkit wizard editor : part 1 : introduction
- microsoft deployment toolkit wizard editor : part 2 : global settings and custom initialization and validation scripts.
- microsoft deployment toolkit wizard editor : part 3 : panes can be a pain, or how to bring external data into your wizard.
this was my reaction when i started trying to figure out the html in the html tab of the wizardeditor
ok, seriously, here is my understanding of what is taking place and how to get data from your xml into the wizard. i welcome all feedback because, well… honestly i am just guessing.
First off this is what the XML that we are loading looks like. I will be referring to this image throughout the explanation
The first part is simple, it is the title of the dialog
<h1>please select correct configuration </h1>
The next item is a div tag with a class assigned to it. Essentially we are creating a section of the document that we can apply style and formatting to using the css defined in wizard.css
.ScrollingDynamicListBox
{
border: solid 1px;
overflow: auto;
width: 600px;
height: 280px;
}
<div class=scrollingdynamiclistbox>
The next line gets a little bit more complex. It declares a table and sets the data source for the table to our XML. Then it sets the height, width and other style elements. If you wanted the html easier to read you could move the style items into the CSS file and just assign a class to the table.
The table tag also says that when the table is ready (full of data) to run the vbscript function ReadyInitializeConfigurationList
<table id="configlist" datasrc="#configurations" height: 300 width="100%" border=0 cellspacing=0
language=vbscript onreadystatechange=readyinitializeconfigurationlist>
The next line specifies a table row and what the table row should look like, what it should look like while the mouse is over it, and sets it back when the mouse leaves the row
<TR = specifies to add a row to our table
Class=”DynamincListBoxRow” = Specifies what our table row should look like
onmouseover=Javascript:this:classname = “DynamicListBoxRow-over” = Says when the mouse is over the row, change the class to DynamicListBoxRow-over
<tr valign=top class="dynamiclistboxrow" onmouseover="javascript:this.classname = 'DynamicListBoxRow-over';"
onmouseout="javascript:this.classname = 'DynamicListBoxRow';" >
There is a lot taking place in these next few lines. It is where we pull the data from our XML and display it in our table. First we use the <TD> Tag to create a “Table Data Cell” and then we use the <INPUT Tag to create a Radio Button and a hidden field in the Data Cell. In the graphic below I added a BORDER to the <TD so you can see there are actually two cell. The one the arrow points to contains our radio button and our hidden field tied to configid
<TD = Creates a Data Cell in our Table row.
<Input type=radio = Creates a Radio Button
<Input Type=hidden = Creates a hidden field to hold our configid value from our XML
The ‘datafld=“configid”’ is what makes ?? insert the value of configid in the xml document into our table-data-cell. I think this is a better explanation than I could provide.
<input type=hidden name=configid datafld="configid" />
<td class=dynamiclistboxelement width="0px">
<input type=radio name=selecteditem language=vbscript onpropertychange="configitemchange" />
<input type=hidden name=configid datafld="configid" />
</td> >
The next few lines create another Data Cell and create two new divisions <DIV> tags (for formatting) and two new <LABEL labels (for data binding) in our document.
The last <LABEL style=”display: inline;”> creates an error message of sorts because it only displays if there is no data. I am not sure of the specifics of how or why it does this so if you know please blog about it and I will link to it HERE.
<td language=vbscript onclick="clickchildcheckbox" class=dynamiclistboxelement width="100%">
<div>
<label datafld="configdescription" class="larger" ></label>
</div>
<div>
<label datafld="configcomments" dataformatas="html">
<label class=errmsg style="display: inline;" >no task sequences are available
(configurations.xml does not exist, is empty, or is inaccessible)
</label>
</label>
</div>
</td>
Then we close our table and our division. Notice there is not a closing </TR> here… it was like that in the pane I based this on. I am not sure if that is an error or intentional. If you know please blog about it and I will link to it HERE.
</table>
</div>
I do not think we are usign this line, I just did not remove it
<input type=hidden id=configidx name=configidx>
And here is the line that brings the XML into our pane
<xml id="configurations"></xml>
And this creates a button that runs the function associaterequestwithmachine vbscript function.
</br>
<div class=wideedit align=center>
<input type=button name="updateconfigbutton" value="tie this machine to the selected configuration" onclick="associaterequestwithmachine" />
</div>
Well, I hope this helped to get you started with the WizardEditor and how to put it to use in your deployment.
If you want to read more about Front Ends for MDT be sure and check out Johan Arwidmark, Maik Koster, Jason Scheffelmaer aka Schuff, and Ben Hunter/The Deployment Guys
I welcome any feedback and corrections,
Todd
Previous Posts in this Series:
- Microsoft Deployment Toolkit Wizard Editor : Part 1 : Introduction
- Microsoft Deployment Toolkit Wizard Editor : Part 2 : Global Settings and Custom Initialization and Validation scripts.
The next items we will examine are Pane Conditions. Conditions specify under what conditions the pane is displayed to the user. The idea is that any information you can provide using CustomSettings.ini or the database will be used, and any values that are missing can be obtained from the user, or simply abort the OS install. Go to the first pane and the first condition. The actual condition is “UCASE(Property("SkipTaskSequence"))<>"YES" “
So what is going to happen with this condition? Wizard.hta is going to send it to the function EvalWithErrorHandling that is defined in WizUtility.vbs. the following graphic shows the lines from Wizard.hta that will send our condition to EvalWithErrorHandling
And here is the function from WizUtility.vbs It sends our condition to the vbscript Eval function.
If our condition evaluates to TRUE, the pane will be shown, if the condition evaluates to FALSE, then the pane will be skipped. this functionality is what will allow us to make our deployment 100% silent if we have all of the information we need, and stop and prompt for information if something we deem critical is missing.
To verify our assumption is correct lets change the condition to something we are fairly sure is true, 1 > 0 and then Save, and then Test our hypothesis by clicking the Test button. If 1 is in fact greater than 0, and if I am correct, the Pane will show.
OK, the pane showed up so reality is safe for now, but just to verify we are correct let’s change it to 0 > 1 (A false statement) and see if we see the SelectTaskSequence Pane
OK, to sum up to this point.. You can add custom scripts using the Initialization action in global, and if a condition evaluates to true a wizard pane will be displayed, if it evaluates to false it will be skipped.
The Validate function works the same way, except it determines if the user gets to LEAVE the pane or not. this can be used to ensure you get the data you need for the deployment to come to a successful conclusion before they can continue.
The Validate function also sends the statement to the eval function as shown below
If the statement is returned as true the Next button will go to the next pane, if it evaluates to false nothing happens. to test this let’s use our 0 > 1 example and see if we can move to the next pane.
be sure you change the condition (not validation) to 1 > 0. If you leave it as 0 > 1 where we left off you will not even see the pane. click test and then click the Next button. You should be stuck on that Pane until 0 > 1
OK, to sum up to this point.. You can add custom scripts using the Initialization action in global, and if a condition evaluates to true a wizard pane will be displayed, if it evaluates to false it will be skipped. If a validation statement evaluates to TRUE the Next button will work, and if the Validation statement is FALSE the next button does not do a thing.
Ok, so now we will examine the Initialization function. The initialization function runs BEFORE the html that defines the page loads. This is where we will go collect data to use in our HTML. The default for SelectTaskSequence is “InitializeTSList”.
The function InitializeTSList is defined in DeployWiz_Initialization.vbs. Recall we specify what other scripts to load using the initialization section in global settings.
Let’s change it to use a new function, let’s call it InitializeCONFIGURATIONListWithSampleFile. Place the function into your DeployWiz_Initialization_CUSTOM.vbs file that is specified on the global initialization
*NOTE* In the first part we made a new file and added it in there, we named it DeployWiz_Validation_CUSTOM.vbs, so you will need to create a new file DeployWiz_Initialization_CUSTOM.vbs and add a new initialization statement in global to load it. Here is the contents of the file I am using. I will not explain what it is doing since it is so obvious.
Function InitializeCONFIGURATIONListWithSampleFile
'Put the XML into our document
'I really do not know what is taking place here so if someone wants to explain it :-)
Set oConfigurationList = oUtility.CreateXMLDOMObjectEx( "Configurations.xml" )
CONFIGURATIONS.XMLDocument.LoadXML oConfigurationList.xml
End Function
Sub ConfigItemChange
document.all.item(window.event.srcElement.SourceIndex + 1).Disabled = not window.event.SrcElement.checked
End sub
Function ReadyInitializeCONFIGURATIONList
' We muck arround with the values, so we need to do some manual cleanup
Dim oInput, oConfigurationList
Dim bFound
ButtonNext.Disabled = TRUE
If Not ConfigList.readystate = "complete" then
Exit function
End If
Set oConfigurationList = document.getElementsByName("ConfigID")
If oConfigurationList is nothing then
oLogging.CreateEntry "oConfigurationList is nothing. Exiting Function", LogTypeInfo
Exit function
End if
If oConfigurationList.Length > 0 then
bFound = FALSE
For each oInput in oConfigurationList
If oInput.Value <> "" and StrComp(oInput.Value,ForceAsString(oproperties("ConfigID")),vbTextCompare) = 0 then
document.all.item(oInput.SourceIndex - 1).click
ButtonNext.Disabled = FALSE
bFound = TRUE
End if
Next
If not bFound And oConfigurationList.Item(0).Value <> "" then
' Just select the first item
document.getElementsByName("SelectedItem").Item(0).click
ButtonNext.Disabled = FALSE
End if
End if
If ForceAsString(oProperties("ConfigID")) <> "" then
oProperties("ConfigID") = ""
End if
End function
Function AssociateRequestWithMachine
MsgBox("You Clicked the Button!")
End Function
Yea, I am not really able to understand much of that either. When I do i will make a new blog post explaining it. That will be at some undetermined time in the future. The code above started out as one of the built in panes provided by MS. I just altered it until it worked for me.
Now we need to alter the html in the html panel so it loads the info from our XML Doc.
First I will show you the entire html, and then I will explain the parts I do understand.
Here is where it goes in the wizard editor
And here is the HTML
<h1>Please Select Correct Configuration </h1>
<div class=ScrollingDynamicListBox>
<table id="ConfigList" datasrc="#CONFIGURATIONS" height: 300 width="100%" border=0 cellSpacing=0
language=vbscript onreadystatechange=ReadyInitializeCONFIGURATIONList>
<tr valign=top class="DynamicListBoxRow"
onmouseover="javascript:this.className = 'DynamicListBoxRow-over';"
onmouseout="javascript:this.className = 'DynamicListBoxRow';" >
<td class=DynamicListBoxElement width="0px">
<input type=radio
name=SelectedItem
language=vbscript onPropertyChange="ConfigItemChange" />
<input type=hidden
Name=ConfigID datafld="ConfigID" />
</td>
<td language=vbscript onclick="ClickChildCheckBox" class=DynamicListBoxElement width="100%">
<div><Label datafld="ConfigDescription" class="Larger" ></Label></div>
<div><Label datafld="ConfigComments" dataformatas="HTML">
<label class=errmsg style='display: inline;' >No task sequences are available (CONFIGURATIONS.xml does not exist, is empty, or is inaccessible)
</label>
</Label>
</div>
</td>
</table>
</div>
<input type=hidden id=ConfigIDx name=ConfigIDx>
<xml id="CONFIGURATIONS"></xml>
</br>
<div class=WideEdit align=center>
<input type=button Name="UpdateConfigButton" value="Tie this machine to the selected configuration" onclick="AssociateRequestWithMachine" />
</div>
At this point you should be able to click Test and see our new data, once you download the configurations.rar and extract the xml file from it and place it in the directory with the rest fo your files
Next Post: What my face looked like when I first tried to decipher the HTML in the HTML Tab!
In my previous post Microsoft Deployment Toolkit Wizard Editor : Part 1 : Introduction we went over what the WizardEditor was, and how to get the files and such required to begin editing a definition XML File. this post begins where that left off.
The first thing will will look at is the global settings.
The most common type of settings for global are CustomStatement, Initialization, and Validation.
A Custom statement will get executed by code in Wizard.hta (snippet below)
'Custom processing within a string
for each item in oXMLDoc.SelectNodes("//Wizard/Global/CustomStatement")
if not ExecuteWithErrorHandling(ITem.TExt) then
window.close
exit sub
end if
next
you can see it will call the function ExecuteWithErrorHandling. You will also notice that function does not exist in Wizard.hta, so where is it? it is in WizUtility.vbs, one of the resource files used by Wizard.hta. Wizard.hta loads WizUtility exposing all of the function in it to the code in the hta
WizUtility.vbs it uses the ExecuteGlobal statement to execute the code in the custom statement.
Function ExecuteWithErrorHandling ( statements )
Dim RunAgain
RunAgain = FALSE
On error resume Next
Err.Clear
ExecuteGlobal statements
ExecuteWithErrorHandling = err.number = 0
RunAgain = DisplayErrorIfAny (statements)
On error goto 0
If RunAgain then
ExecuteGlobal statements
End if
End function
So to sum up, you can execute any vbscript code you like, and use any function in either WizUtility or ZTIUtility without editing any of the scripts supplied in MDT just by putting the code into a CustomStatement in the Global section. This will allow you to customize your solution and be able to upgrade the scripts and such without needing to rewrite them all.
The “Initialization” setting is similiar to the CustomStatement because they both use ExecuteGlobal.
Here is how the Wizard uses the file(s) specified in Initialization section “ ExecuteWithErrorHandling(oFso.OpenTextFile(srootDir & Item.TExt ,ForReading,FALSE).ReadAll) ”. Essentially it reads the entire vbs file and sends it to the ExecuteGlobal statement
the “Validation” statement in the global section does, as far as I can tell, the exact same thing the Initialization section does. I cannot figure out why there are two different types. If you know please shoot me an email or leave a comment
So what is the significance of this? you can write your own vbscript with your own functions in it without modifying the MDT scripts.
Make a new vbscript file and put it in the directory with the rest of the sample files. I named mine DeployWiz_Validation_CUSTOM.vbs. then Make a new action of type initialization as shown below
Then set the name of the vbs file.
Next Post: Panes can be a pain, or how to bring external data into your wizard.
The Microsoft Deployment Toolkit Wizard Editor (WizardEditor.exe) is a free open source program hosted on CodePlex.
WizardEditor is used to edit the XML definition files that define the dialogs that Wizard.hta displays and under what conditions they are displayed. Using the WizardEditor it is possible to build a custom Front End to interact with humans in your OS Deployment. The wizards it creates can be used in lite touch or with a TS in ConfigMgr/SCCM/CM. In this tutorial we will create a simple wizard that will run prior to our TS starting when booting to boot media in an SCCM OSD Deployment.

Screencap of Wizard.hta running BDD_Welcome_ENU.xml
To get a better idea of how to use WizardEditor to create our own custom Front Ends we will need to go over how Wizard.hta interacts with the other files. The following diagram shows how they tie together.
LiteTouch.vbs Purpose: Start the lite touch deployment process
LiteTouch.vbs does two main things, it runs ZTIPrereq.vbs to ensure the machine meets the prerequisites and then it launches LiteTouch.wsf
LiteTouch.wsf Purpose: Drive the lite touch deployment process
LiteTouch.wsf performs quite a few functions. Everything from correcting drive letters to setting the deployment phase and finding the deployment root. The two main items we are concerned with is it runs ZTIGather.wsf to process the CustomSettings.ini file then it launches the Wizard.hta and specifies the Definition XML that the wizard will use.
Wizard.hta
Purpose: Display a wizard to the user Wizard.hta loads and processes the XML file.
DeployWiz_Definition_ENU.xml
the XML Definitions file defines what Wizard.hta displays and under what circumstances
DeployWiz_Initialization.vbs
Purpose: Initialize wizard panes used in the deployment wizard. This file contains the functions used by the “initialize” actions you specify in the definition xml file
DeployWIz_Validation.vbs
Purpose: Validate wizard panes used in the deployment wizard. This file contains the functions used by the “validate” actions you specify in the definition xml file
WizUtility.vbs
Purpose: Common Utility functions used by UI Scripts
General purpose scripts and files used. See MDT documentation for an explanation
- CustomSettings.ini
- ZTIUtility.vbs
- ZTIGather.wsf
- ZTIPrereq.vbs
If you want to follow along with this tutorial download the files I am starting with Front End Wizard Example.
Please note, line 465 of DeployWiz_Initialization.vbs was altered to make it load the TaskSequences.xml from the current directory rather than Control so do not use the included scripts except with this demo
'Set oTSList = RemoveNonEnabledElements( Property("DeployRoot") & "\Control\TaskSequences.xml" )
Set oTSList = RemoveNonEnabledElements( "TaskSequences.xml" )
1.) Open WizardEditor.exe and browse to the definition file you want to edit
{insert text so I do not look too stupid if I post errors}
I need to say a few things at this point:
I am not a professional developer. The target audience of this article is other Sys Admins. If you are a professional developer (or Maik) I have no doubt you will find errors in what follows. If you do see any and would like to help please send me a clarification or blog about it and send me the link and I will place a link to it here.
Links to corrections/explanations: {none so far}
My goal is to provide folks with enough information to get them started with a fundamental understanding of what is happening and what to do. I struggle with many of the concepts and code in these scripts so do not take anything that follows as fact, it is just “how Todd sees it today”.
Now that the Definition.xml is loaded click the “Test” button in the WizardEditor. When you run a test the wizard editor will do a few things to get the environment ready for a test:
// Tell the user if there are pending changes that need to be saved first. (Tells you to save the XML file if you modified it)
// Clean up from previous execution (Deletes the log files from C:\MININT\SMSOSD\OSDLOGS)
// Run ZTIGather.wsf if it can be found
// Launch ZTIGather.wsf to get information about the current machine. Have it shove in a few default
// values too for DeploymentType, DeploymentMethod, and DeployRoot so that the wizard works better.
// Now run Wizard.hta if it can be found
// Make sure the required files are present in the same directory
{ "Wizard.hta", "Wizard.css", "WizUtility.vbs", "Wizard.ico", "BackButton.JPG", "ZTIUtility.vbs" }
// Launch Wizard
Since it will run ZTIGather.wsf we will want to see what CS.ini file it is using. to do this open the BDD.log in C:\MININT\SMSOSD\OSDLOGS and find the value
Now lets test the xml and see if it will load up before we make any changes. click the “Test” button. After running ZTIGather the wizard should load as shown below
If you cannot get it to run read the logs and try to determine the issue. Note: If you leave any of the logs open in Trace WizardEditor.exe will generate an error and exit. Make sure you do not have a handle on any of the files it needs before testing.
Next Post: Global Settings and Custom Initialization and Validation scripts.