MDT 2012 – Taking LiteTouch Offline

I decided to give some of my user base something that they have been asking for for a long time… the ability to run MDT/LiteTouch deployments entirely from removable storage media. I had avoided doing this in the past as we made significant use of the MDT database in selecting hardware-specific support applications (such as Dell QuickSet).  However, with MDT 2012 (and the general deprecation of hardware-specific support software under Windows 7), I have decided to abandon the MDT database.  This makes generation of offline MDT media much more feasible.

“I should be able to get this done in a few hours!”, I thought.  Ha!  Four days later…

Gotchas in adding LiteTouch Offline media to a previously online-only environment:

Expiring stale media:

One of the leading arguments we make to persuade users to adopt the use of LiteTouch is that “we keep it up to date for you”.  What about offline media?  How to we ensure that that stays current?  One of the Brad Tucker, Deployment Guy, has a solution for that:

http://blogs.technet.com/b/deploymentguys/archive/2012/02/15/expiring-outdated-stand-alone-media.aspx

The problem there is that his script was developed for the SCCM ZTI scenatio, not LiteTouch.  However, with a little work I was able to adapt his script for use in LiteTouch.  The script body is available below.  To run it, I needed to modify the “winpeshl.ini” file in %ProgramFiles%\Microsoft Deployment Toolkit\Templates as follows:

[LaunchApps]
%SYSTEMROOT%\System32\wscript.exe,X:\Deploy\Scripts\ZUVMExpiredMediaCheck.vbs
%SYSTEMROOT%\System32\bddrun.exe,/bootstrap

The script referenced above (ZUVMExpiredMediaCheck.vbs) needs to be defined in the “Extra Directory to Include” field in the WinPE section of the Media set in the Deployment Workbench.  You need to include the “\Deploy\Scripts” folder structure in the Extras directory, too.

WinRE installation problems:

Since deploying MDT 2012, I finally worked though the problem of including both WinRE and MS DaRT tools into the LiteTouch boot media, and in the WinRE environment installed with the operating system.  However, with offline media the inclusion we would not want to copy the LiteTouch WinPE instance to disk.  Two reasons.  Firstly, the OS Deployment option simply would not work (Offline media would not be available), and secondly, we just included a script to disable the media.  To solve this problem, I needed to set the “PrepareWinRE” Property in the CustomSettings.ini file for the media set to “NO”.

MS DaRT Integration Problem:

When testing LiteTouch from a fully offline machine, I started to get a “network connection not available” error pop up at seemingly random places after starting up the boot media.  Eventually I realized that the error was coming from the DaRT Remote Connection tool that starts up with WinPE.  While this error does not cause any problems with actual deployment, I don’t want it causing end-user panic, so I decided to see if I could disable the feature.  According to documentation, I need to generate a “DartConfig.DAT” file using the DaRT configuration tool.  DartConfig.DAT is a binary configuration file (not plain text).  It’s options are not documented anywhere, so you really do have to run the GUI tool to generate a new DAT.  You then are supposed to drop the DAT file into “%ProgramFiles%\Microsoft Deployment Toolkit\Templates”, and update your boot media.  A few problems with this:

  1. If you want different configuration files installed into your WinPE instances, you will either to switch out the DartConfig.dat in the Templates directory each time you update boot media, or run the updates from a different MDT instance, or edit the LiteTouch boot WIM files each time you update the boot media.  There is no way to specify different DartConfig.dat files per deployment share or media set.
  2. The Deployment Workbench does not consistently insert the DartConfig.dat file into the LiteTouch boot media.  If you update your DartConfig.dat in the Templates directory, then update your boot media, there is no guarantee that your DartConfig.dat will get updated.  The only sure-fire way to get a new DartConfig in your deployment share seems to be to force regeneration of the boot media (i.e. you need to throw out your existing boot WIM files, not update them).  The situation is worse with offline media sets.  Rather the workbench will copy any existing boot WIMs from the root deployment share to serve as a baseline image when generating offline boot images.  Thus, to update DartConfig.dat in a media set, you need to delete both the root share boot WIMs, and the offline boot WIMs prior to updating media.
  3. You might think that you could work around that whole one-template-per-workbench problem by including a per-media-set DartConfig.dat in the “Extras” folder that you can optionally include in each media set or deployment share.  After all, the media update procedure appears to add the extras after the templates.  But if you did think this, you would be wrong.  The update apparently will not overwrite existing files within the source WIM.
  4. You might, out of sheer desperation, decided to remove DaRT from the offline boot media  by deselecting the component from the WinPE properties of the media set.  This also will fail.  The workbench will report that “DaRT cannot be removed from the media.  Use the -Force option to regenerate the media.”  Presumably the error is suggesting that you should add “-force” to the Update-MDTMedia PowerShell Cmdlet that is used to update the media set.  Sadly, “-Force” is not a valid flag for this cmdlet.

Ultimately, I just used imagex to mount the LiteTouch Offline boot media, and switched out the DartConfig.dat file using a simple “copy” command.  Now I just need to remember to do that every time.

UserExit Script – Required Modifications:

Back in 2008 I added a UserExit script to LiteTouch to generate a semi-unique computer name by taking the last eight characters of the computer’s MAC address, then appending a hyphen and a date string.  It turns out that the routine in MDT that captures the MAC address (presumably ZTIGather.vbs) will not succeed unless the computer has a functional Ethernet connection.  Grrr… When testing LiteTouch offline, we were getting computer names like “Address%-1214″.  Percent characters are not valid in computer names  so, I needed to update our UserExit to use other semi-unique system attributes such as “Serial Number” to “Asset Tag” if the MAC is not available.  I also added a fallback string of “UVMLT” if none of those variables are found.  The new script is available below, along with a sample call to the script from CustomSettings.ini.


' // ****************************************************************************
' // File:      ZUVMExpiredMediaCheck.vbs
' // Version:   1.0
' // Purpose:   Check to see if stand-alone media is expired
' // Actions:   Shuts down WinPE if media is older than iExpAge variable months
' //            Otherwise, script exits with Return 0.
' // Usage:     cscript/wscript ZUVMExpiredMediaCheck.vbs
' //            (to be added to winpeshl.ini, before bddrun.exe)
' // ****************************************************************************
Option Explicit

' // Declare Variables:
Dim cFiles
Dim dtCreationDate, dtEndDate, dtXMonthsAgo
Dim iExpAge
Dim oDiskDrive, oDrives, oExec, oFile, oFSO, oShell, oWMIService
Dim sCommand, sComputer, sExpText, sSysRoot, sUSBPath

' // Initialize Variables:
' Media Expiration Age, in months:
iExpAge = 4

' // -----------------------------------------------------------------------------------------
' // Function: Converts the WMI date query response to a simple date format.  (e.g. 09/21/2010)
Function WMIDateStringToDate(dtmInstallDate)
	WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & Mid(dtmInstallDate, 7, 2) _
	& "/" & Left(dtmInstallDate, 4) & " " & Mid(dtmInstallDate, 9, 2) & ":" _
	& Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, 13, 2))
End Function
' // -----------------------------------------------------------------------------------------

' // ---------------------------------------------------------------------------------
' // Find the environment variable %SYSTEMROOT% for location of LiteTouch Executables.
Set oShell = CreateObject("WScript.Shell")
sSysRoot = oShell.ExpandEnvironmentStrings("%SYSTEMROOT%")
' // ---------------------------------------------------------------------------------

' // --------------------------------
' // Find driver letter for USB Media
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oDrives = oFSO.Drives
For Each oDiskDrive In oDrives
	If oDiskDrive.DriveType = "1" Then
		sUSBPath = oDiskDrive.Path
	End If
Next
' // --------------------------------

' // -------------------------------------------------------------------------
' // Media Check - Check for Applications.xml presence and age.
sComputer = "."
Set oWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & sComputer & "\root\cimv2")
' Query WMI for creation date of the Applications.xml file on the USB Drive:
'    NOTE: Do not add the wbemFlagForwardOnly (Decimal 32) flag to this query.  While the query would run faster
' with the flag, we also will not be able test for empty queries.
Set cFiles = oWMIService.ExecQuery("Select * From CIM_DataFile Where Name = '" & sUSBPath & "\\Deploy\\Control\\Applications.xml'")
' // -------------------------------------------------------------------------

' // ---------------------------------------------------------------------------------
' // If Applications.xml file is not present, this is not offline media.  Exit script.
if cFiles.Count = 0 then
	Wscript.Quit(0)
end if
' // ---------------------------------------------------------------------------------

' // ---------------------------------------------------------------------------------------------
' // If the Applications.xml file creation date is more than "iExpAge" months ago, shutdown WinPE.
For Each oFile in cFiles
	dtCreationDate = WMIDateStringToDate(oFile.CreationDate)
	dtEndDate = DateAdd("m", iExpAge, dtCreationDate)
	' Set the date iExpAge months ago from today
	dtXMonthsAgo = DateAdd("m", -iExpAge, Now)
	If dtCreationDate < dtXMonthsAgo then
		' Expiration Text, to be displayed to the user if older than iExpAge months:
		sExpText = "This LiteTouch Offline Media expired on: " & dtEndDate & chr(13) _
			& "Refresh your media using the README file located here:" & chr(13) _
			& "\\files.uvm.edu\software\Windows_Deployment_Services"
		MsgBox sExpText,vbMsgBoxSetForeground,"Expired Media"
		'Shutdown WinPE immediately:
		sCommand = sSysRoot & "\system32\wpeutil.exe shutdown"
		set oExec = oShell.Exec(sCommand)
	Else
		' If the media is fresh, run LiteTouch Offline.
		WScript.Quit(0)
	End If
Next
' // ---------------------------------------------------------------------------------------------

' // ZUVMUserExit.vbs
' // Custom Function library for use with the Microsoft Deployment Toolkit
' // Currently includes "GenUniComp" - a function for generating unique computer names

' code adapted from source content:
'   http://blogs.technet.com/benhunter/archive/2007/03/17/understanding-bdd-rule-processing.aspx

Function UserExit(sType, sWhen, sDetail, bSkip)
	UserExit = Successfs
End Function

Function GenSimDate(sSimDate)
	'Generates a simple date string in the format of YYMMDD
	Dim dNow, sYear, sMonth, sDay
	dNow = Date()
	sYear = Right(cStr(Year(dNow)), 2)
	sMonth = cStr(Month(dNow))
	sDay = cStr(Day(dNow))
	GenSimDate = sYear + sMonth + sDay
End Function

Function CleanMac(sMac)
	'Strips colon (:) characters from the variable passed to this function.  The passed variable is presumed to be a Mac address.
	Dim oRegExp
	Set oRegExp = new RegExp
	oRegExp.IgnoreCase = true
	oRegExp.Global = true
	oRegExp.Pattern = ":"
	CleanMac = oRegExp.Replace(sMac, "")
End Function

Function GenUniComp(sMac,sSerial,sATag)
	'Generates a hopefully unique computer name by:
	'   Selecting from available MacAddress, SerialNumber, or Asset Tag then
	'   triming the right eight digits from the value and appending a hyphen with the current date.
	Dim sSimDate, sUniVal
	oLogging.CreateEntry "ZUVMUserExit: sMac value in UserExit script is: " & sMac,LogTypeInfo
	oLogging.CreateEntry "ZUVMUserExit: sSerial value in UserExit script is: " & sSerial,LogTypeInfo
	oLogging.CreateEntry "ZUVMUserExit: sATag value in UserExit script is: " & sATag,LogTypeInfo
	if InStr(sMac,"%Mac") = 0 then
		oLogging.CreateEntry "ZUVMUserExit: Using Mac Address to generate computer name",LogTypeInfo
		sMac = CleanMac(sMac)
		oLogging.CreateEntry "ZUVMUserExit: Cleaned sMac values now is: " & sMac,LogTypeInfo
		sUniVal = sMac
	elseif InStr(sSerial,"%Serial") = 0 then
		oLogging.CreateEntry "ZUVMUserExit: Using Serial Number to generate computer name.",LogTypeInfo
		sUniVal = sSerial
	elseif InStr(sATTag,"%Asset") = 0 then
		oLogging.CreateEntry "ZUVMUserExit: Using Asset Tag to generate computer name.",LogTypeInfo
		sUniVal = sATag
	else
		oLogging.CreateEntry "ZUVMUserExit: Using Fallback Computer Name",LogTypeInfo
		sUniVal = "UVMLT"
	end if
	oLogging.CreateEntry "ZUVMUserExit: sUniVal now set to: " & sUniVal,LogTypeInfo
	sSimDate = GenSimDate(sSimDate)
	GenUniComp = Right(sUniVal, 8) + "-" + sSimDate
	oLogging.CreateEntry "ZUVMUserExit: Unique Computer Name will be: " & GenUniComp,LogTypeInfo
End Function

Calling the GenUniComp function from CustomSettings.ini:

ComputerName=#GenUniComp("%MacAddress%","%SerialNumber%","%AssetTag%")#

Comments are closed.