Todd Hemsell at myITforum.com

{Enter witty eye catching description here}

March 2009 - Posts

My Dee Dee Dee moment, or “What is a loopback adapter?”

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.

Microsoft Deployment Toolkit Wizard Editor : Part 4 : What my face looked like when I first tried to decipher the HTML in the HTML Tab!

previous posts in this series:

  1. microsoft deployment toolkit wizard editor : part 1 : introduction
  2. microsoft deployment toolkit wizard editor : part 2 : global settings and custom initialization and validation scripts.
  3. 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

Monkey_Shocked

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

image

 

The first part is simple, it is the title of the dialog

image

<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

 image

         <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

image

<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.

image

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

Microsoft Deployment Toolkit Wizard Editor : Part 3 : Panes can be a pain, or how to bring external data into your wizard.

Previous Posts in this Series:

  1. Microsoft Deployment Toolkit Wizard Editor : Part 1 : Introduction
  2. 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"

image

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

image

And here is the function from WizUtility.vbs It sends our condition to the vbscript Eval function.

image

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.

image

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

image

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

image

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.

 image

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

image

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”.

image

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

image

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

image

Next Post: What my face looked like when I first tried to decipher the HTML in the HTML Tab!

Microsoft Deployment Toolkit Wizard Editor : Part 2 : Global Settings and Custom Initialization and Validation scripts.

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.

image

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

image

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.

image

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

image

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

image

Then set the name of the vbs file.

image

Next Post: Panes can be a pain, or how to bring external data into your wizard.

Microsoft Deployment Toolkit Wizard Editor : Part 1 : Introduction

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.

Screenshot of the MDT Wizard

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.

LiteTouchWizardFlow

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

image


{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

image

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

image

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.