Michael Niehaus' Windows and Office deployment ramblings
There have been some blog postings talking about how to add the Hyper-V integration components into Windows PE. The first from Mike Sterling, available at http://blogs.msdn.com/mikester/archive/2008/05/30/using-the-hyper-v-integration-components-in-winpe.aspx, talks about the manual way of going about this. Then the Deployment Guys, specifically David Hornbaker, talked about how to do this with MDT 2008 in his posting at http://blogs.technet.com/deploymentguys/archive/2008/06/12/adding-hyper-v-integration-components-to-winpe-using-mdt-2008.aspx. But with MDT 2008 Update 1, we can improve this process and fix some of the challenges that David alludes to in his post. (I'll point these out below.)
First you need the Hyper-V integration components from the "VMGUEST.ISO". The easiest way to do this is from inside a virtual machine: mount the ISO and extract the needed Windows6.0-KB951634-x86.msu file into a new, empty directory. (See the other blog entries for details.) Then you need to first extract the x86 drivers:
MD MSU expand Windows6.0-KB951634-x86.msu -F:*.CAB MSU MD Files expand MSU\Windows6.0-KB951634-x86.cab -F:* Files
MD MSU expand Windows6.0-KB951634-x86.msu -F:*.CAB MSU
MD Files expand MSU\Windows6.0-KB951634-x86.cab -F:* Files
(I skipped David's steps that rearranged the files and cleaned up the temporary working directories. You can choose to do those if you like.) Here's what it would look like (except for the output of the final command):
Repeat the steps for the x64 drivers too, using a different new, empty directory because some of the file and directory names will be the same:
MD MSU expand Windows6.0-KB951634-x64.msu -F:*.CAB MSU MD Files expand MSU\Windows6.0-KB951634-x64.cab -F:* Files
MD MSU expand Windows6.0-KB951634-x64.msu -F:*.CAB MSU
MD Files expand MSU\Windows6.0-KB951634-x64.cab -F:* Files
Not surprisingly it will look it looks just like the x86 output, just with different directory and file names:
The final EXPAND command for both x86 and x64 should show 305 files extracted (at least if you are using the Hyper-V RTM integration components; the number may change in the future):
One important note: If you try this on Windows Server 2003 or Windows XP, it may not work properly because these operating systems contain earlier versions of EXPAND.EXE and related DLLs. You won't see any errors or any other indication that the process didn't work; the resulting file count will be much smaller. Ideally, use Windows Vista or Windows Server 2008 to do the extraction. (If you are desperate, you could copy the EXPAND.EXE, DPX.DLL, and MSDELTA.DLL files from a Windows Server 2008 OS or image. Place these files into the empty directories you create above, then make sure you run them by specifying ".\EXPAND.EXE" so that Windows doesn't find them in the system path first.)
This sounds like it should be really easy, and it almost is. First, import the x86 integration component drivers , pointing to the directory "files" directory you created above (in my case, "C:\x86\Files"). Create a new driver group called "Windows PE Drivers" and be sure to import the drivers into that group:
Now look at the results of that import:
Notice that some of the drivers say that they are for both x86 and x64 platforms. Well, that's not actually true, as these are only x86 drivers. So we'll take advantage of a new MDT 2008 Update 1 feature to de-select the x64 platform for each of these drivers. Right click on each of the drivers and choose "Properties," then uncheck the "x64" checkbox:
Now we need to repeat this same process for x64 drivers, this time selecting the "c:\x64\Files" directory and the "Windows PE Drivers" group created previous. But there's one other important item: You need to check the "Import drivers even if they are duplicates of an existing driver" box:
If you didn't do this, Deployment Workbench will think the drivers are already present and won't import them again. It checks for duplicates based on the class, manufacturer, and version. In this case, all of those values are the same so we wouldn't import the drivers again. By checking the box, they'll all get imported anyway.
You'll notice now that there are again some that say they are for x86 and x64. Uncheck the "x86" checkbox for these newly-imported drivers since they are all x64 drivers.
You should now have this full list of drivers:
Notice the paths for each of the drivers: The ones with the "_(1)" suffix wouldn't have been imported if you didn't check the "import duplicates" box. (This also points out another change in MDT 2008 Update 1: We no longer create driver directories containing spaces in them. This is related to a problem with the processing of [SysprepMassStorage] sections by sysprep.exe on Windows XP or Server 2003. More on that some other time.)
With all the needed drivers in place, we just need to tell Deployment Workbench to use them. Open the properties of the lab deployment point and specify the "Windows PE Drivers" group you created previously. (Be sure to check the "x64" box on the General tab if you want x64 images.) Also specify to "Include all drivers from the selected driver group":
This "include all drivers" checkbox is another new feature in MDT 2008 Update 1. Without this checkbox, we could only inject mass storage, network, video, and system-class drivers. With this, we'll inject all the drivers in the specified group. Why does this matter? Well, in this case we want to be sure to inject the HIDClass drivers you can see in the above list. HID stands for "human interface device." This is the driver that enables mouse integration so that you no longer need to press Control-Shift-Left Arrow all the time you are working in Windows PE.
Also make sure that you have added all the existing drivers, at least for networking and mass storage, into the same "Windows PE Drivers" group, otherwise your Windows PE boot images will work on Hyper-V but not on any machine requiring other out-of-box drivers.
Now, you can "Update" the deployment point to generate the new images containing the drivers that were imported in the previous step and selected in this one. Want to see the proof that they were all injected? Check the %TEMP%\DeployUpdates_x86.log (or %TEMP%\DeployUpdates_x64.log for the x64 boot image) to see each of them being imported. (Search for "/inf=" to find the right lines.)
In David's blog he mentioned that you would need to create the Windows PE images in separate steps. He was talking about using two different driver groups, one for x86 containing the x86 drivers and one for x64 containing the x64 drivers. This was necessary for two reasons:
The first reason is really needed because of the second. But now since MDT 2008 Update 1 allows you to override the platform on each driver, you can again get back to a single driver group - both problems solved.
Now that there are Hyper-V drivers included in Deployment Workbench, they will also be injected into the full OS. That's less than desirable because we really want the Hyper-V drivers to be installed in the full OS using the integration components. So if you want to prevent this, you can create a new driver group containing all the non-Hyper-V drivers. (Yes, if you have lots of drivers this is a fairly painful process as you need to select the new group by opening the properties of each driver individually.)
Once you've created this group, e.g. "Full OS Drivers", you need to tell the MDT scripts to only use this group. There's no user interface in the task sequence editor to specify this, but you can add it to CustomSettings.ini (on the Rules tab of the deployment point):
If you skipped this step, it probably wouldn't hurt anything, but you do want to make sure the integration components are installed afterwards.
Now we need to install the integration components themselves. (Yes, this isn't related to Windows PE, but hey, go back and read the title: it's not all about Windows PE). The easiest way to do this is to set them up as an application. In Deployment Workbench, create a new application with source files (so we don't need to worry about mounting the VMGUEST.ISO), pointing to the "e:\support\x86" directory (where E: is my DVD drive in the VM) that contains all the needed files. For the command line, specify "setup.exe /quiet /norestart". After the application has been added, modify the properties to specify "Reboot the computer after installing this application". (If you want, you can also modify the platform restrictions so this application is only seen on supported OSes.)
Repeat the same process for the x64 integration components, pointing to the "e:\support\amd64" directory.
With these applications created, you can now select them in the Lite Touch deployment wizard. If you want to automate this by adding the application into the task sequence, you can certainly do that instead (hiding the applications from the wizard at the same time).
With these pieces in place, it should be that much easier to work with MDT 2008 Update 1 and Hyper-V. When I started writing this up (a long time ago, before MDT 2008 Update 1 was even released) I didn't think it would take so long. And I'm sure I didn't need to be quite so verbose...
For those of you who attended my driver management sessions at MMS 2009 and TechEd 2009 US, you know that Dell is planning to provide CAB files for many of their machines, starting with the corporate laptop models. These are “raw” drivers, provided in a CAB file that saves you the hassle of trying to figure out how to download and extract the contents of dozens of different packages for each model. Now, one CAB file contains all the files you need, just extract the contents of the CAB and import them into your driver repository of choice (MDT 2008, MDT 2010, ConfigMgr, WDS R2, etc.).
See http://www.delltechcenter.com/page/Dell+Business+Client+Operating+System+Deployment+-+The+.CAB+Files for the list of models that now have CAB files posted (there are quite a few).
Once MDT 2010 Beta 2 comes out, you won’t even need to extract the contents of the CAB files. Deployment Workbench will automatically extract the CAB file contents into a temporary folder and then import each driver that it finds.
If you are upgrading from BDD 2007 (any version) to MDT 2008, the instructions are covered in the "Getting Started Guide" included with MDT 2008. So I won't repeat that discussion here. I want to focus on the new scenario, upgrading from the original Microsoft Deployment to the new Microsoft Deployment Toolkit 2008. Here are the basic steps:
MDT 2008 does not require Windows AIK 1.1 if you are using only Windows Vista RTM, Windows XP, or Windows Server 2003; Windows AIK 1.0 is fine for these. But if you are using Windows Vista SP1 or Windows Server 2008, you need to upgrade to Windows AIK 1.1. (If you don't, as soon as you add a Windows Vista SP1 or Windows Server 2008 image, you'll start seeing warning dialogs. They won't go away until you do upgrade.) The steps needed to upgrade to Windows AIK 1.1 are:
That should do it. Now you're ready to start with Windows Vista SP1 and Windows Server 2008 :-)
Some people noticed that during an OS deployment task sequence, performed either by MDT 2008 Lite Touch or by ConfigMgr, could capture sensitive information (from unattend.xml, variables.dat, etc.) as part of the automatic System Restore snapshot process that happens whenever a new driver, application, security update, etc. is installed.
To address that issue, we added some logic in MDT 2010 to disable System Restore by configuring the default unattend.xml template:
<component name="Microsoft-Windows-SystemRestore-Main" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DisableSR>1</DisableSR> </component>
We then added logic to re-enable that at the end of the deployment process – but only for Lite Touch. (You can see that logic in LTICleanup.wsf.) We discovered later that this was left out of the ConfigMgr scripts. So as a result, machines deployed using ConfigMgr and an MDT 2010 task sequence template ended up with System Restore disabled.
In MDT 2010 Update 1, we added logic to address this. Now, System Restore will be re-enabled at the end of the deployment even with ConfigMgr. (Because we don’t have the equivalent of LTICleanup.wsf in a ConfigMgr task sequence, the logic was added to ZTICopyLogs.wsf, the last script to run during an OSD task sequence.)
(10527)
I’ve always been a fan of the thinnest image possible. Taking that to an extreme, that means using the original image straight off the Microsoft media. But over time if you did this you’d find that the time required to apply patches to that image becomes unmanageable. (Case in point: I started up a new laptop for the first time with an OEM-installed image that had hooks to require all patches be applied before first logon. It took three hours for that to happen.)
I’ve also been a fan of doing “just in time” patching, which is something that MDT can do too: Instead of patching the image in advance, you can inject updates offline after the image has been applied to the disk but before it boots for the first time. That does often improve the time required, but it doesn’t eliminate it – it adds time when initially injecting the updates offline, and then more time on first boot as the “online actions” for those “offline patches” are completed (you’ll see the messages on the screen during the first boot showing a percentage complete while this is happening).
So reading between the lines, that means I would suggest always creating your own master image containing at least all the current service packs and patches. (Don’t try to install the OS service pack yourself – just download “slipstreamed” media from the Microsoft licensing website, as that’s the ultimate time-saving technique.) So how should you do this? Well, there are a few ways:
Not surprisingly, MDT 2010 Lite Touch provides a way to implement my preferred method above – and actually multiple methods that can be used. Let’s go through those methods.
This is the easy way, as long as you have good internet bandwidth (all updates are downloaded from the internet) and a direct path to these downloads (as we don’t really support proxy servers in the MDT task sequence), and always want to install all critical updates. (We skip language packs, drivers, and service packs by default, and you can exclude additional updates, but the exclusion process requires a little work.)
To use this method, all you need to do is search your task sequence for the following steps:
Enable both of them, and then build a new image – that’s all there is to it. (Why are there two steps you ask? Well, the first might be required in order for the subsequent application installs to complete; the second might be required to patch the applications, e.g. Office, after it’s installed. If the second step doesn’t need to install any additional patches, it won’t take very long.)
To give you better control over patched put into your image, you may only want to install approved updates. If you are using Windows Server Update Services (WSUS), then you already have such an approval mechanism in place, all you need to do is tell the task sequence to talk to WSUS instead of going to the internet. This is pretty simple too:
Make sure that you have configured WSUS to install updates on unknown computers, because when building a reference computer it is indeed unknown to WSUS at the point the task sequence is executing.
This one is probably the most work, primarily because you need to manually download all the updates that you want to install, and it only works for OS updates (as they are the only ones that can be injected offline). The steps required:
When the task sequence runs, the “Apply Patches” will identify all the updates for the OS and platform being deployed, download them to the client, and update the unattend.xml to inject them. (SETUP.EXE will later call DISM.EXE to do the actual injection after the image has been extracted and applied to the hard drive.) If you want to apply a particular set of patches, you can configure a selection profile with one or more folders containing those updates, then configure the “Apply Patches” step to use that selection profile.
Well, that’s a completely different discussion. Some people do a new image monthly (and probably don’t do much testing on that image each time they recreate it). Some do it every few months. Some do it once a year. You just need to balance the efforts required to build it (easy), test it (not quite so easy), and distribute it (can be really painful) against the added time of applying some updates later.
You can actually use any (or all) of the above methods in that “later” deployment task sequence too:
Some additional links that might be useful:
Windows Update in MDT 2010 « Xtreme Deployment
Approving Windows Updates in an MDT 2010 Standalone Environment
A new hotfix for USMT 4.0 was released today to support migrating Office 2010 settings. (It includes other fixes too.) You may want to download this and integrate it into your deployment processes. The full instructions for doing this (including what needs to be done with MDT and ConfigMgr) are included in the KB:
http://support.microsoft.com/kb/2023591
There is one complication that you should be aware of if you are using ConfigMgr and moving from Windows XP or deploying Windows XP. USMT 4.0 uses a set of manifest files to determine what needs to be migrated from Windows XP. These manifest files are stored in the “DLManifests” folder, which is part of your USMT package in ConfigMgr. There is an issue though where Scanstate.exe can’t find this DLManifests folder when run from ConfigMgr. In MDT 2010 Update 1, we included a workaround for this with some logic in ZTIUserState.wsf, copying the folder where Scanstate can find it:
' Workaround for USMT bug in Windows 7 AIK If oEnvironment.Item("DeploymentMethod") = "SCCM" and oEnvironment.Item("OSVersion") = "XP" and oFSO.GetFileVersion(sFoundScanState) = "6.1.7600.16385" then oUtility.RunWithHeartbeat "cmd.exe /c xcopy /iesryhd """ & sUSMTPath &"\DlManifests"" """ & oEnv("SystemRoot") & "\system32\DlManifests" &""" 1>> " & oLogging.LogPath &"\zticopyUSMT.txt 2>>&1 " End if
Notice that this checks specifically for build 6.1.7600.16385 of Scanstate.exe, the version released in the Windows 7 version of Windows AIK, as we expected this problem to be fixed in the next version of USMT. Well, it wasn’t. But once you install the KB 2023591 hotfix, the version changes to 6.1.7601.21645 and our fix stops working.
You can work around this by fixing the fix in ZTIUserState.wsf to read like this:
If oEnvironment.Item("DeploymentMethod") = "SCCM" and oEnvironment.Item("OSVersion") = "XP" and (oFSO.GetFileVersion(sFoundScanState) = "6.1.7600.16385" or oFSO.GetFileVersion(sFoundScanState) = "6.1.7601.21645") then
If you aren’t using ConfigMgr or don’t have Windows XP around any more, you won’t need to worry about this.
If you’ve done ConfigMgr OS deployments, you’ve probably seen an error dialog like this before:
Pretty simple, right? Distribute this package to a local DP and then try again. But there are often dozens (or in extreme cases, hundreds) of packages referenced by the package, so you might have to go through this cycle a few times before you get them all. Fortunately, there are some ConfigMgr WMI classes that can help figure out which packages are missing. With a little bit of PowerShell logic, we can automate the whole process, through these basic steps:
This process will take care of boot images, OS images, OS install packages, driver packages, software update packages, or any other type of packages that are referenced (because behind the scenes, packages are packages to ConfigMgr – only the UI differentiates).
The scripts needed to this are attached to this blog. You’ll need to save the SCCM.psm1 file in an appropriate PowerShell module folder (see the comments in the script for more details) so that the CheckTaskSequences.ps1 script can find it (and of course you’ll have to enable PowerShell script execution using something like “Set-ExecutionPolicy RemoteSigned”). Then, just run CheckTaskSequences.ps1 each time you create a new task sequence. It will very quickly identify the packages that need to be distributed and take care of those for you.
Note: Version 1.1 of the script is now attached (using version 1.5 of SCCM.psm1) to address a couple of bugs found in the current version. See the comments in CheckTaskSequences.ps1 for more information.
This seems to be a frequent question that comes up:
“I am working with PCs from <vendor> that have model strings that frequently change, although the first part is always consistent. How can I use these models with the MDT database without creating a new entry for each unique string?”
This seems to come up most often with computers from Lenovo, where the first four characters indicate the model and the last three indicate a specific configuration of that model. It’s also seen with various HP computers, although their pattern tends to be a little more difficult.
The “gather” process that MDT uses doesn’t provide a way to do wildcard or “like” queries, but it does provide extensibility to let you define your own property to use instead of “Model” when querying the database. Let me give a “real world” example for the Lenovo case. I can use a CustomSettings.ini like this:
[Settings] Priority=CalculateCustom, MMSettings Properties=CustomModel [CalculateCustom] CustomModel=#Left("%Model%", 4)# [MMSettings] SQLServer=MNiehaus-T61p-7 Instance=SQLExpress Database=MDTDatabase Netlib=DBNMPNTW SQLShare=DeploymentShare$ Table=MakeModelSettings Parameters=Make, CustomModel CustomModel=Model
[Settings] Priority=CalculateCustom, MMSettings Properties=CustomModel
[CalculateCustom] CustomModel=#Left("%Model%", 4)#
[MMSettings] SQLServer=MNiehaus-T61p-7 Instance=SQLExpress Database=MDTDatabase Netlib=DBNMPNTW SQLShare=DeploymentShare$ Table=MakeModelSettings Parameters=Make, CustomModel CustomModel=Model
This defines a new property called “CustomModel”. It includes a rule that has a very simple manipulation: it sets the value to the first four characters of the existing “Model” value, which in the case of my T61p laptop results in a value of “6458”.
I then modified the database query to tell it to use “CustomModel” as a parameter instead of “Model”. If that’s all I did, the query would fail because it would create a SQL statement that specified “WHERE CustomModel = ‘6458’” but that’s not valid since there isn’t a CustomModel column in the database. That’s where the next line comes in:
CustomModel=Model
This says that the property “CustomModel” as we know it locally is called “Model” in the database. As a result, the correct query is generated:
About to issue SQL statement: SELECT * FROM MakeModelSettings WHERE MAKE = 'LENOVO' AND Model = '6458' Successfully queried the database.
That’s all it takes. Now, there would typically be more than just the [MMSettings] section that needs the “CustomModel” updates – you would also want to change [MMPackages], [MMApps], [MMAdmins], and [MMRoles] the same way.
If you need to do a calculation that is more complex than the simple substring that I implemented above, you may need to use a user exit to do the calculation. The end of the exit just needs to set the same “CustomModel” property. The rest of the logic would be the same. So you could use something like this for the exit:
Function UserExit(sType, sWhen, sDetail, bSkip) If sType = "SECTION" and sWhen = "BEFORE" then oLogging.CreateEntry "Calculating custom model string.", LogTypeInfo If UCase(oEnvironment.Item("Make")) = "LENOVO" then oEnvironment.Item("CustomModel") = Left(oEnvironment.Item("Model"), 4) ElseIf Instr(oEnvironment.Item("Model"), "(") > 2 then oEnvironment.Item("CustomModel") = Trim(Left(oEnvironment.Item("Model"), Instr(oEnvironment.Item("Model"), "(") - 2)) Else oEnvironment.Item("CustomModel") = oEnvironment.Item("Model") End if End if UserExit = Success End Function
Function UserExit(sType, sWhen, sDetail, bSkip)
If sType = "SECTION" and sWhen = "BEFORE" then
oLogging.CreateEntry "Calculating custom model string.", LogTypeInfo
If UCase(oEnvironment.Item("Make")) = "LENOVO" then oEnvironment.Item("CustomModel") = Left(oEnvironment.Item("Model"), 4) ElseIf Instr(oEnvironment.Item("Model"), "(") > 2 then oEnvironment.Item("CustomModel") = Trim(Left(oEnvironment.Item("Model"), Instr(oEnvironment.Item("Model"), "(") - 2)) Else oEnvironment.Item("CustomModel") = oEnvironment.Item("Model") End if
End if
UserExit = Success
End Function
Save that as “CustomModelExit.vbs” in the same “Scripts” directory with ZTIGather.wsf, then edit the CustomSettings.ini to specify to run it:
[Settings] Priority=CalculateCustom, MMSettings Properties=CustomModel [CalculateCustom] UserExit=CustomModelExit.vbs [MMSettings] SQLServer=MNiehaus-T61p-7 Instance=SQLExpress Database=MDTDatabase Netlib=DBNMPNTW SQLShare=DeploymentShare$ Table=MakeModelSettings Parameters=Make, CustomModel CustomModel=Model
[CalculateCustom] UserExit=CustomModelExit.vbs
The only change from the previous CustomSettings.ini sample is the [CalculateCustom] section. Now it specifies the run the user exit script. So what exactly does this script do? Well, if it’s a Lenovo machine, it takes the first four characters. If the models string contains a starting parenthesis, “(“, it will chop everything from that point off of the model (e.g. “My Model (Test)” will become “My Model”). In any other case, the script will assign the current model value to the CustomModel property. (That simplifies things somewhat.)
You might need to tweak the script some based on your specific requirements, but the basic setup should work for whatever manipulation you would like to do.
We have seen lots of requests over the past couple of years for a wizard pane that allows you to select from a list of roles that should be applied to a machine, where those roles are defined in the MDT database. There are a few examples of this available on the web, implemented in different ways. I’ll throw another one into the mix, this one using an ADO.NET Data Services web service to get the needed data. (If you didn’t read my previous posting about this setup, click here.)
<?xml version="1.0" encoding="utf-8"?> <Wizard> <Global> <CustomStatement><![CDATA[ ' *************************************************************************** ' File: Roles.xml ' Author: Michael Niehaus ' Version: 1.0 ' Purpose: Display a list of roles from the MDT database, retrieved ' using an ADO.NET Data Services.web service. One ' or more roles can be selected. After they have been ' chosen, CustomSettings.ini needs to be re-processed ' to pick up the new settings. Ideally this would be done ' after the wizard is complete (just in case someone ' navigated back to the screen after initially making ' changes), but that requires changing LiteTouch.wsf. ' ' NOTE: Be sure to modify the web service URL below ' ' *************************************************************************** Function InitializeRoleList Dim sScript Dim oDataService Dim oRole Dim sRoles ' Make sure that ZTIDataAccess.vbs is available since it isn't loaded by Wizard.hta sScript = oFSO.OpenTextFile(oUtility.ScriptDir & "\ZTIDataAccess.vbs", 1, false).ReadAll On Error Resume Next ExecuteGlobal sScript On Error Goto 0 ' Call the web service Set oDataService = New WebService oDataService.WebService = "http://localhost:62932/MDTDatabase.svc/RoleIdentity" oDataService.Method = "REST" Set oResult = oDataService.Query ' Process the roles to populate the list of checkboxes sRoles = "" For each oRole in oResult.SelectNodes("//d:Role") sRoles = sRoles & "<input type=checkbox name=Roles id=Roles enabled value='" & oRole.Text & "'>" & oRole.Text & "</input><br>" Next ' If no roles were found, set the div to indicate that If sRoles = "" then sRoles = "<label class=errmsg style='display: inline;' >No roles could be found." End if ' Update the pane RoleList.InnerHTML = sRoles End Function Function ValidateRoleList ' Flush the value to variables.dat, before we continue. SaveAllDataElements SaveProperties ' Process full rules (needed to pick up the role settings, apps, etc.) sCmd = "wscript.exe """ & oUtility.ScriptDir & "\ZTIGather.wsf""" oItem = oShell.Run(sCmd, , true) ValidateRoleList = True End Function ]]></CustomStatement> </Global> <Pane id="Roles"> <Body><![CDATA[<H1>Select the roles to be assigned to this computer.</H1> <br> <div class=TreeList id=RoleList style="height: expression( GetDynamicListBoxSize(this) );"> <label class=errmsg style="display: inline;" >Loading roles... <!-- List goes here --> </div> ]]></Body> <Validation><![CDATA[ValidateRoleList]]></Validation> <Initialization><![CDATA[setTimeout GetRef("InitializeRoleList"), 0]]></Initialization> </Pane> </Wizard>
<?xml version="1.0" encoding="utf-8"?>
<Wizard>
<Global>
<CustomStatement><![CDATA[
' ***************************************************************************
' File: Roles.xml
' Author: Michael Niehaus
' Version: 1.0
' Purpose: Display a list of roles from the MDT database, retrieved
' using an ADO.NET Data Services.web service. One
' or more roles can be selected. After they have been
' chosen, CustomSettings.ini needs to be re-processed
' to pick up the new settings. Ideally this would be done
' after the wizard is complete (just in case someone
' navigated back to the screen after initially making
' changes), but that requires changing LiteTouch.wsf.
'
' NOTE: Be sure to modify the web service URL below
Function InitializeRoleList
Dim sScript
Dim oDataService
Dim oRole
Dim sRoles
' Make sure that ZTIDataAccess.vbs is available since it isn't loaded by Wizard.hta
sScript = oFSO.OpenTextFile(oUtility.ScriptDir & "\ZTIDataAccess.vbs", 1, false).ReadAll
On Error Resume Next
ExecuteGlobal sScript
On Error Goto 0
' Call the web service
Set oDataService = New WebService
oDataService.WebService = "http://localhost:62932/MDTDatabase.svc/RoleIdentity"
oDataService.Method = "REST"
Set oResult = oDataService.Query
' Process the roles to populate the list of checkboxes
sRoles = ""
For each oRole in oResult.SelectNodes("//d:Role")
sRoles = sRoles & "<input type=checkbox name=Roles id=Roles enabled value='" & oRole.Text & "'>" & oRole.Text & "</input><br>"
Next
' If no roles were found, set the div to indicate that
If sRoles = "" then
sRoles = "<label class=errmsg style='display: inline;' >No roles could be found."
' Update the pane
RoleList.InnerHTML = sRoles
Function ValidateRoleList
' Flush the value to variables.dat, before we continue.
SaveAllDataElements
SaveProperties
' Process full rules (needed to pick up the role settings, apps, etc.)
sCmd = "wscript.exe """ & oUtility.ScriptDir & "\ZTIGather.wsf"""
oItem = oShell.Run(sCmd, , true)
ValidateRoleList = True
]]></CustomStatement>
</Global>
<Pane id="Roles">
<Body><![CDATA[<H1>Select the roles to be assigned to this computer.</H1>
<br>
<div class=TreeList id=RoleList style="height: expression( GetDynamicListBoxSize(this) );">
<label class=errmsg style="display: inline;" >Loading roles...
<!-- List goes here -->
</div>
]]></Body>
<Validation><![CDATA[ValidateRoleList]]></Validation>
<Initialization><![CDATA[setTimeout GetRef("InitializeRoleList"), 0]]></Initialization>
</Pane>
</Wizard>
While this is set up as a stand-alone wizard, you can insert this into an existing deployment wizard using the MDT Wizard Editor by following these steps:
What, your MDT Wizard Editor doesn’t have a “Paste” option? Well, you need to download a new version from http://mdtwizardeditor.codeplex.com/, as I just added the paste capability tonight (along with other general usability improvements – I forced myself to actually use the program to create the rules wizard pane above and fixed all the behaviors I didn’t like while I was at it).
A few notes to mention:
Those of you who deploy both x86 and x64 versions of Windows 7 using MDT 2010 Lite Touch probably know that you have to use two different boot images to do it: When booted from a Lite Touch x86 boot image, you only see task sequences associated with x86 operating systems; when booted from a Lite Touch x64 boot image, you only see task sequences associated with x64 operating systems.
With MDT 2012 Beta 1, that’s been changed. Now, if you boot from a Lite Touch x86 boot image you will see all task sequences, whether x86 or x64.
But there is one “gotcha”: If you choose a task sequence that deploys an x64 OS, MDT will need to find a copy of the corresponding x86 setup files and it will then use those to install the x64 OS. So you need to make sure that you have x86 setup files in the deployment share (with one of the operating systems), even if you aren’t deploying that operating system. It needs to match the version (e.g. 6.1.7601.17514) of the x64 OS that you are deploying. (This is the really the same as if you were deploying a custom image. Now, we just make sure we pick a copy of setup files that match the Windows PE platform being used, ignoring those that don’t, even if they are provided with the OS being deployed.)
The other combination, booting from an x64 boot image and deploying an x86 OS, isn’t supported by Windows Setup, so we still hide x86 task sequences when you have booted into an x64 boot image.