In the last two articles Create your custom Boot Wizard - some advanced stuff and Create your own Boot Wizard - Display dynamic data we created a Custom Boot Wizard which requests a list of available OSD Task Sequences (we actually get the collections the Task Sequences are advertised to) and shows this dynamic list to the user to chose from. In this article we now will create a script which will call our custom Boot Wizard and process the results of the users choice.
If you deploy a Boot Image via WDS/PXE or CD you can configure it in a way to execute something, before the "real" process (The Task Sequence) starts. This is called "pre-execution Media Hook". Sounds groovy but it's quite simple. During the startup it will look for a file called "TSConfig.ini" in the root of the Boot image. If this file exists it will be processed. Now you can add a section like
[CustomHook]
CommandLine="wscript.exe x:\Deploy\Scripts\ZTIMediaHook.wsf"
to this file and it will execute the Script "ZTIMediaHook.wsf" which is located at x:\Deploy\Scripts. X:\ is the path to the Boot Image. We will first go through this script to see what it does for us. At the end I will show you how you can add this file, the Boot Wizard and all supporting script files to your Boot image.
OK, let's start with the script. You will recognize that it looks quite similar to other MDT Scripts. In most cases it is the easiest to take an existing script and just change it the way you want it to have. This way you don't need to pay much attention on being compliant with the MDT Standards. We will skip the header and look at the "Main routine".
On Error Resume Next
iRetVal = ZTIProcess
ProcessResults iRetVal
On Error Goto 0
This simply executes the Function "ZTIProcess" and call a MDT Internal function called "ProcessResults" with the return value. Skip this for now. Important is only that it calls the function ZTIProcess. Now we have a look on the ZTIProcess Function:
Function ZTIProcess()
Dim iRetVal
Dim sCmd
Dim sAssignedSite
Dim iCount
iRetVal = Success
oEnvironment.Item("DeploymentMethod") = "SCCM"
sCmd = "wscript.exe """ & oUtility.ScriptDir & "\ZTIGather.wsf"" /inifile:SCCM_Bootstrap.ini"
iRetVal = RunAndLog(sCmd, true)
So far nothing important. Just some standard variables and we call ZTIGather.wsf with the "SCCM_Bootstrap.ini" file which has already been mentioned in the last article. We do this to gather some values we need for further processing like IP Address, MAC Address, etc.
oEnvironment.Item("AssignedSite") = GetAssignedSite
If IsNothing(oEnvironment.Item("AssignedSite")) Then
oLogging.CreateEntry "Unable to determine assigned site.", LogTypeWarning
Else
oLogging.CreateEntry "Client is assigned to site " & oEnvironment.Item("AssignedSite"), LogTypeInfo
End if
Here we get the assigned Site of the Computer which is required by the wizard to get the list of collections. The Assigned Site will be returned by the custom Function "GetAssignedSite":
Function GetAssignedSite
Dim oService
Dim oXML
Set oService = new WebService
oService.IniFile = "SCCM_Bootstrap.ini"
oService.SectionName = "GetSCCMAssignedSite"
Set oXML = oService.Query
If oXML Is Nothing Then
oLogging.CreateEntry "Unable to call GetSCCMAssignedSite web service.", LogTypeWarning
Else
GetAssignedSite = UCase(oXML.SelectSingleNode("string").Text)
End if
End Function
Again it queries a webservice with the following definition:
[GetSCCMAssignedSite]
WebService=http://YourWebServer/Deployment/AD.asmx/GetSCCMAssignedSite
In this case, I chose to query AD for the AssignedSite. If SCCM information is not published to AD you can also find a corresponding webservice for SCCM which will call the SLP to get the necessary information. Now we go ahead with the ZTIProcess function:
If Not HasOSDAdvertisement Then
sCmd = "MSHTA.exe """ & oUtility.ScriptDir & "\Wizard.hta"" /definition:CustomBootWizard.xml"
RunAndLog sCmd, true
If oEnvironment.Item("WizardComplete") <> "Y" Then
oLogging.CreateEntry "User has canceled the wizard. Exiting!", LogTypeInfo
Exit Function
End If
Else
oLogging.CreateEntry "Computer has already an Advertisement. Skipping Wizard.", LogTypeInfo
Exit Function
End If
Here we will execute the wizard only, if there isn't already a Task Sequence available for that computer (I will skip this function as it looks almost identical to "GetAssignedSite". Just find it in the download for the complete source). The wizard is called by a function called RunAndLog. Again this is a Function which comes with MDT (even if it needs to be available within the Script "ZTIMediaHook.wsf) and can be found in the download.It just adds some common logging functionality. Not really something which gives us some more information here so lets also skip this. After the user has finished the wizard, we need to check if he canceled the wizard, in that case we should also cancel the further processing, or chose collection.
Now to the core functionality:
If AddComputerToCollection Then
oLogging.CreateEntry "Waiting for Advertisement", LogTypeInfo
WScript.Sleep 5000
For iCount = 1 To 20
oLogging.CreateEntry "Sleeping 5 seconds to wait for an OSD Advertisement (Attempt " & iCount & " of 20).", LogTypeInfo
WScript.Sleep 5000
If HasOSDAdvertisement Then
oLogging.CreateEntry "Found an OSD Advertisement, continuing ...", LogTypeInfo
WScript.Sleep 3000
Exit For
End If
Next
End If
This finally will add the computer to the collection and then wait until the advertisement is available for the computer. This typically takes only a couple of seconds but depending on the current load of the server also up to a couple of minutes. You can adjust the timing to your needs. That's it! The called functions "AddComputerToCollection" and "HasOSDAdvertisement" again are quite similar to the "GetAssignedSite". Quite useless to repeat similar stuff so just download the solution and have a look on the complete Scripts and SCCM_Bootstrap.ini.
End Function
;-)
This was a quite simple example. Typically you need to include additional information into the wizard and probably a bit more complex process to decide what to do, etc. But this is meant as a start to your own wizards. As soon as you understand how the different parts work together it's easy to extend it. Or just ask for help.
However, the last step is now to include all this information into a Boot Image. We first start with a new Boot Image.
As this is about MDT, we will create our Boot Image using MDT. Before we actually create the image, some actions are necessary. First, have a look at the installation folder of the "Microsoft Deployment Toolkit" (typically within Program Files). You should find a subfolder called "SCCM". In there you will find some of the files used for the original MDT Wizard. You probably recognize the "ZTIMediaHook.wsf" and "SCCM_Bootstrap.ini" files. During this articles we simply used the same names. You will also find the "TSConfig.ini" file mentioned at the beginning of this article. As we stick to the same names MDT is using to execute its wizard there is now need to create our own, so we can use the on contained in this folder.
We could now simply copy our custom files into this folder to have them included into the Boot image. I personally prefer to not touch any original stuff (Have fun if you install an Update :-) ). So we will use a different way for adding our files. To do this, we need to create a folder which will contain our files. As we need to supply the path to this folder later via its UNC path, create it on a network share. Preferably the share which is already hosting all your Reference files. During the creation of the Boot image with MDT we will have the option to add an additional folder to the image. The content of the path will be copied to the root of the Boot image. So if you have a file just in this folder it will be available in the root. I use this e.g. to add files like Trace32.exe and some others for easier troubleshooting. OK, lets say you have a folder "\\YourFileServer\Packages$\MDT\Additional_Files" within this folder create a Folder called "Deploy" and within this a new folder called "Scripts". That's the path MDT will store its files so we just use the same. Now copy all your custom Scripts, the wizard xml file, the SCCM_Bootstrap.ini and what else you would like to have in there into this folder.
If you are done with this, it's now time to create the new Boot image. First you need to create another folder to store the Boot Image itself. Again, it needs to be on a networks share. For this example it will be \\YourFileServer\Packages$\MDT\Custom_Boot_Image. Now open the ConfigMgr Console and expand the "Operating System Deployment" Node. Right click on the node "Boot Images" and choose "Create Boot Image using Microsoft Deployment".
It will now open a wizard which will help you creating your new Boot Image. First you need to supply the path where the new Boot image shall be stored. Just type in the UNC Path of the folder us just created
Next supply a name, version and comment for the Boot image. On the next Screen
you have the possibility to enable support for the pre-execution Hook (just check the "Add media hook files ..." option) and supply the path for our Additional Folder. You don't need to take care about the text field with the "Web service URL" as we will overwrite the SCCM_Bootstrap.ini file anyway :-). (btw. don't forget to adjust the SCCM_Bootstrap.ini to your environment. If you just downloaded it it will contain a generic path to http://YourWebServer/Deployment/...) .Adjust the rest of the options to your needs. After finishing the Wizard it will then create two files. a WinPE.wim and a WinPE.PackageID.wim. The second is the one which will be distributed by SCCM. You will notice that it is noticeable larger as it contains additional SCCM binaries and the Drivers you added (or will add) to the Boot image. So the WinPE.wim is the reference which is used by SCCM to create the second one. If you mount the WinPE.wim with imagex you can verify that all files from our "Additional Folder" have been added to the Boot image and that the original files from MDT have been overwritten.
Now the drawback. If you "Update" the Boot image in SCCM, changed files from the "Additional folder" or the MDT Folder will not be updated in the wim :(
There are two ways to update your files
- Recreate the image instead of updating. Just delete the old Boot image, and Create a new one. The problem with this is that you need to add it again to the DPs where you need it and the PXE Shares. You also would need to change the Boot Image in each Task Sequence which used the old one.
- The method I prefer! Mount the image, make the changes and commit them and then update the Boot image in SCCM.
The second way isn't actually very complicated. To do what I suggested just
- Create a new Folder to mount the image (e.g.: C:\Mount)
- Mount the wim with imagex (It's part of the WAIK which has (or should) already been installed on your SCCM Server. Or install it on your computer. You probably need a couple more things from the WAIK if you digg into Deployments :-)) using "imagex /mountrw Path_and_Name_to_the_winPE.wim 1 C:\Mount". "/mountrw" mounts the wim in read/write mode so that you can make changes to the wim. The 1 in the commandline specifies the first image within the wim file (wim files can contain several images) and C:\Mount is the folder we just created
- Open C:\Mount and do all the changes necessary. Adding new files, etc.
- Unmount the wim and commit the changes with "imagex /unmount /commit C:\Mount"
After you have changed the wim just Update the Boot Image in the console and all changes will now be integrated into the Boot image used by your Task Sequences and it will be deployed to all your DPs and PXE Shares.
As mentioned already in the last article, you will find all files, scripts etc. on our new codeplex page http://mdtcustomizations.codeplex.com/ (Download example files). It is a repository for MDT Scripts, Front ends, Web services and Utilities for use with ConfigMgr/SCCM. Also be aware that you need to adjust some files you downloaded to your environment. Specifically the SCCM_Bootstrap.ini file needs to be changed to that that Webservice definitions are pointing to the Webserver which is hosting the webservice in your environment.
See also
Create your custom Boot Wizard - make it available for all known and unknown Computers
Using a custom Boot Wizard to boot known and unknown computers in SCCM and choose a Task Sequence to run - Step by Step