Michael Niehaus' Windows and Office deployment ramblings
I was finally shamed into it by several of the MyITForum guys: I took the 70-401 certification exam, "TS: Microsoft System Center Configuration Manager 2007, Configuring", and yes, I passed with flying colors. I actually liked the exam: nothing too fancy, lots of questions around OS deployment (my favorite), troubleshooting, software distribution, software updates, network access protection, etc. Even though there are some portions that I rarely (if ever) do in my day job (e.g. network access protection, internet-facing clients, software updates, reporting) I still knew enough about the concepts and implementation to get the answers. Practical experience with the product is definitely required.
Now I need to figure out which exams to take next. I think it's time to look at the new Windows Server 2008 exams, working towards getting the "MCITP: Enterprise Administrator" certification, or maybe the 70-660 "TS: Windows Internals" exam.
I've given a variety of presentations at past TechEd and MMS events (as well as our own internal TechReady conferences) talking about making deployments more dynamic. One of the scenarios discussed was dynamic package installation with ConfigMgr 2007. The idea is that you want to install the same software in the new OS that was present in the old OS (assuming that list is different on each computer, most always the case), so the user can be immediately productive once the deployment is complete. The basic steps:
Something similar can be done with Lite Touch, but you can't use inventory. Instead, you just have to inspect the machine to see what is present and select the appropriate applications based on what you found. (Granted, this only works for refreshes because you need access to the current OS to get the list of apps. This isn't the case with the ConfigMgr solution, since the inventory is already on the server. But that's OK in this case - if you want more capabilities, you really need to look at moving to ConfigMgr anyway.)
First, you need a way to detect the presence of applications. The same mechanism used with ConfigMgr works here too: look at the Add/Remove Programs entries. But where can you specify the ARP key name that should be associated with an application? MDT (and BDD 2007 before that) provides a place to do that:
Just specify the key name in the "Uninstall registry key name" box. (Yes, for MSI-based installers this will be a GUID.) Normally this field is used during the deployment to keep MDT from trying to install an application that is already present on the machine, but we can leverage it here too.
Then, you need to tell MDT what to do with the information. That requires a little scripting. Save the VBScript code below (watch out for line wrapping) to a file called LTIAppDetect.vbs and place that file in the \Distribution\Scripts folder:
Option Explicit Function UserExit(sType, sWhen, sDetail, bSkip) Dim oXMLDoc, oNode, oKey Dim sValueName, sKey, sValue Dim oApplications ' Only do this before processing the rule contents If sWhen <> "BEFORE" then UserExit = Success Exit Function End if ' Load the applications XML File Set oXMLDoc = CreateObject("MSXML2.DOMDocument") oXMLDoc.load oEnvironment.Item("ResourceRoot") & "\Control\applications.xml" ' Enumerate the applications For each oNode in oXMLDoc.selectNodes("//application") ' Retrieve the uninstall key node if present Set oKey = oNode.selectSingleNode("UninstallKey") ' If one was specified, look for the key in the registry If not (oKey is nothing) then ' Get the key name sKey = oKey.Text ' Check if the registry key exists by looking for well-known values For each sValueName in Array("DisplayName", "UninstallString", "QuietUninstallString") sValue = empty on error resume next sValue = oShell.RegRead("HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName) on error goto 0 If IsEmpty(sValue) then On error resume next sValue = oShell.RegRead("HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName) On error goto 0 End if ' If a value was found, add the application's GUID to the list so it gets pre-selected by the wizard If not isempty(sValue) then oLogging.CreateEntry "Uninstall registry key found for application " & oNode.selectSingleNode("Name").Text & ", application is present and will be reinstalled.", LogTypeInfo ' Add the GUID if it doesn't already exist in the list Set oApplications = oEnvironment.ListItem("Applications") If not oApplications.Exists(oNode.Attributes.getNamedItem("guid").value) then oApplications.Add oNode.Attributes.getNamedItem("guid").value, "" oEnvironment.ListItem("Applications") = oApplications End if Exit For End if Next Else oLogging.CreateEntry "UninstallKey not specified for application " & oNode.selectSingleNode("Name").Text, LogTypeInfo End if Next UserExit = Success End Function
Function UserExit(sType, sWhen, sDetail, bSkip)
Dim oXMLDoc, oNode, oKey Dim sValueName, sKey, sValue Dim oApplications
' Only do this before processing the rule contents
If sWhen <> "BEFORE" then UserExit = Success Exit Function End if
' Load the applications XML File
Set oXMLDoc = CreateObject("MSXML2.DOMDocument") oXMLDoc.load oEnvironment.Item("ResourceRoot") & "\Control\applications.xml"
' Enumerate the applications
For each oNode in oXMLDoc.selectNodes("//application")
' Retrieve the uninstall key node if present
Set oKey = oNode.selectSingleNode("UninstallKey")
' If one was specified, look for the key in the registry
If not (oKey is nothing) then
' Get the key name
sKey = oKey.Text
' Check if the registry key exists by looking for well-known values
For each sValueName in Array("DisplayName", "UninstallString", "QuietUninstallString")
sValue = empty on error resume next sValue = oShell.RegRead("HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName) on error goto 0
If IsEmpty(sValue) then On error resume next sValue = oShell.RegRead("HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" & sKey & "\" & sValueName) On error goto 0 End if
' If a value was found, add the application's GUID to the list so it gets pre-selected by the wizard
If not isempty(sValue) then
oLogging.CreateEntry "Uninstall registry key found for application " & oNode.selectSingleNode("Name").Text & ", application is present and will be reinstalled.", LogTypeInfo
' Add the GUID if it doesn't already exist in the list
Set oApplications = oEnvironment.ListItem("Applications") If not oApplications.Exists(oNode.Attributes.getNamedItem("guid").value) then oApplications.Add oNode.Attributes.getNamedItem("guid").value, "" oEnvironment.ListItem("Applications") = oApplications End if
oLogging.CreateEntry "UninstallKey not specified for application " & oNode.selectSingleNode("Name").Text, LogTypeInfo
UserExit = Success
Now you need to tell MDT to call the script. Because we want to run this before displaying the Deployment Wizard, we can't add it to the task sequence. Instead, we'll set this up as a user exit to be called during the gathering process. Modify CustomSettings.ini to include this:
(Don't remove anything, just add the one new UserExit line). Now, when you perform a Lite Touch deployment, ZTIGather.wsf will call the LTIAppDetect.vbs user exit script, it will find what applications you have currently (at least those with "uninstall registry key" matches in the MDT applications list), and it will update the "Applications" list to include those applications. These will then show up in the Deployment Wizard pre-selected, and as a result will be installed by the task sequence once the new OS is installed. (If the user really doesn't want them any more, they can de-select them in the wizard.)
A couple of notes:
Anyone interested in a webcast on Windows Vista performance? Mark Russinovich is hosting a roundtable discussion webcast tomorrow morning, part of the Springboard series, at 9 a.m. Pacific time with a panel of IT pro experts: customers, partners, MVPs, etc. It should be a good discussion, focusing on common causes of Windows Vista performance problems and how to improve overall system performance. There will be live Q&A toward the end of the session, so start thinking of questions.
For more information, visit https://ms.istreamplanet.com/springboard/.
p.s. If you missed the previous security-focused virtual roundtable, check that one out too.
The name is slightly changed this year (no more "IT Forum" in the name, to align better with the TechEd US event), but the same great content. See the http://www.microsoft.com/emea/teched2008/itpro/ website for the details, and be sure to check out the session list at https://emea.msteched.com/itpro/public/sessions.aspx. It's not a complete list of sessions yet, plenty of surprises yet to come. It's always a great conference, and in a great location (Barcelona), and this year will be no exception.
And of course Microsoft Deployment Toolkit will be covered in several sessions, including discussions on the new version we're working on. We'll likely give the first public demo at the conference :-)
Several people have asked me how the unknown computer support in ConfigMgr R2 works. I can honestly say I don't know because I haven't had a chance to try it yet. (I've been busy on other things.) Fortunately, Steve Rachui has had time to explore the new capabilities and has posted two blog entries explaining how to use it:
Just be careful when using mandatory advertisements with the R2 unknown computer support: those will deploy a new OS to any unknown computer. There are two ways that you can avoid accidentally reimaging a machine:
So there's one scenario where you might want to continue using the MDT 2008 unknown computer support, even if you are running ConfigMgr R2: if you want to respond to unknown computers with a mandatory advertisement but only on a certain subnet (e.g. only in a staging room). You can edit the MDT PXEFilter.vbs script to do such filtering, but R2 don't offer any filtering.
Today was the annual Microsoft Company Meeting, where all the Seattle-area employees get together in one of the few places big enough to hold us all, Safeco Field (home of the Seattle Mariners). This year, the event was hosted by Rainn Wilson (http://movies.msn.com/celebrities/celebrity-biography/rainn-wilson/), a Seattle native. It was appropriate enough then that we got to see the premier of the new "I'm a PC" commercials that were shown during The Office this evening, part of the new "Life Without Walls" advertising campaign.
The YouTube version:
Or, if you prefer a version not hosted by Google, the MSN Soapbox version:
There are a total of three commercials out now, plus billboards and other adds. If anyone is going through JFK airport and sees the video screen ads there, tell us what they look like :-)
We talked about all kinds of new technologies, but many are still secret (and impressively enough, we were all trusted to not spill the beans). There are a few exceptions, though, for items already out in pre-release forms:
Since the release of Windows Server 2008 and Hyper-V I've been going through withdrawal as I wasn't running any beta software. Now things are ramping up again - lots of things to look forward to.
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...
If you've noticed a 90-second delay added between each package installed by a task sequence (whether from individual "Install Software" steps installing single packages or from a single "Install Software" step processing a variable list) since installing SP1 or certain pre-SP1 hotfixes, you'll be interested in the fix documented at http://support.microsoft.com/kb/955955. (Be sure to click on the "View and request hotfix downloads" link at the top of the page. That way you don't have to call Microsoft Support to get the fix.)
I gave two presentations at TechEd New Zealand in Auckland and five sessions at TechEd Australia in Sydney this week. Now I think I need to take a vacation to recover - too bad I just got back from vacation. Anyway, both conferences were great, both cities were great, and it's now back to the office to do some real work. (Sadly, I had one failed demo: a simple ConfigMgr bare metal XP deployment. Oops, the machine generated a new computer object and wasn't in the collection. I then tried to use a different VM, but that failed too with an error 1168. For future reference, that's the error you'll see if you try to run a task sequence on a VM that doesn't have even a single disk attached to it.)
One video I saw this week during the conference was fairly entertaining.
Yes, it's humor only IT geeks would enjoy. And yes, since I enjoyed it I'm admitting I'm an IT geek. But there's nothing wrong with that. (I especially like the part about 1:20 into the video.)