Michael Niehaus' Windows and Office deployment ramblings
Be sure to read the great new posting on the “Building Windows 8” blog:
http://blogs.msdn.com/b/b8/archive/2011/09/07/bringing-hyper-v-to-windows-8.aspx
(Read through the comments too, which talk about support for sleep and hibernate.)
There is one prominent statement made:
Hyper-V requires a 64-bit system that has Second Level Address Translation (SLAT).
That means you have a great reason to consider using the 64-bit version of Windows 8, and why you should buy only hardware with 64-bit support. But what about the second part of that, SLAT support? Well, all you really need to understand is that SLAT is a processor feature that improves virtual machine performance, especially when using higher-end video cards (e.g. those used on client machines). Read more about the benefits in the Hyper-V R2 announcement:
http://technet.microsoft.com/en-us/library/dd446676(WS.10).aspx
This mentions that Intel and AMD have different implementations of this. Intel calls theirs “Enhanced Page Tables” (EPT), while AMD refers to it as “Nested Page Tables” (NPT). Regardless, what you really care about is whether or not a particular processor includes the support. That’s not always easy to figure out from the vendor’s web sites. Fortunately, there is a newly-updated tool available on the SysInternals web site called Coreinfo that will tell you all about a processor’s capabilities:
http://technet.microsoft.com/en-us/sysinternals/cc835722
Mark Russinovich updated this utility recently to add the ability to detect both Intel EPT and AMD NPT. Here’s what the output would look like if your machine has an Intel processor with the needed support:
The AMD output will be slightly different (and not because it’s on a white background instead of a black one):
In both cases, the asterisk (“*”) in the second column indicates that the feature is present. (A minus, “-“, shows if it isn’t.) Be careful if running this in a VM or on a machine currently running a hypervisor, as these will mask the real processor capabilities.)
So check out your machines today to see if they are ready for Windows 8 client Hyper-V!
If you are trying to install multiple software packages using a ConfigMgr task sequence "Install Software" step, where each of the package and program combinations is stored in a task sequence variable (e.g. PACKAGES001=XXX00001:Install), you might find that they don't work. If you go digging through the SMSTS.LOG, you'll see messages like this:
No matching policy assignments received.Policy download failed, hr=0x80004005
This is because you have to give ConfigMgr permission to install a package that isn't advertised to the computer. (ConfigMgr always tries to be "secure by default" and making this the default would violate that principle.) This is done using the "Allow this program to be installed from the Install Software task sequence without being advertised" checkbox on each program's properties. The explanation given in the ConfigMgr documentation (http://technet.microsoft.com/en-us/library/bb680842.aspx) is:
Important The program specified must have the Allow this program to be installed from a list of software packages in the "Install Software" task sequence step without being advertised option selected or the installation will fail. This option can be selected when adding a program to an existing package in the New Program Wizard. Alternatively, you can specify this option by right-clicking an existing program, selecting clicking Properties, and then clicking the Advanced tab.
Important
The program specified must have the Allow this program to be installed from a list of software packages in the "Install Software" task sequence step without being advertised option selected or the installation will fail. This option can be selected when adding a program to an existing package in the New Program Wizard. Alternatively, you can specify this option by right-clicking an existing program, selecting clicking Properties, and then clicking the Advanced tab.
So, before you can install a dynamic list of packages, you need to check this box on every program that you are planning to install this way. Depending on how many programs you have, this could be rather painful via the ConfigMgr console. So in MDT 2008 Update 1, we included a new sample script to help with this (a script I forgot to mention in my previous post). Look in the "C:\Program Files\Microsoft Deployment Toolkit 2008\Samples" folder for a file named EnableProgramsForTS.vbs. You will need to make a few edits toward the top of this script before it will work in your environment:
sProviderServer = ""sSiteCode = "CEN"sNamespace = "root\sms\site_" & sSiteCodesUsername = ""sPassword = ""
Change these values to specify the proper connection details for your ConfigMgr site (whichever site owns packages that need updating, typically the central primary site) and then run it. (Don't specify a username and password if you are running the script on the ConfigMgr server. These values are always optional, but when making a local WMI connection they can't be specified.) The script will check the "Allow" box for every program on every package.
If there is a subset of programs that you want to enable, you can tweak the script as required. (Of course if the criteria is too complex it's probably easier to just use the UI.)
I mentioned in the blog post at http://blogs.technet.com/b/mniehaus/archive/2012/07/21/mdt-2012-update-1-always-applying-images-with-imagex.aspx that MDT 2012 Update 1 no longer uses SETUP.EXE to install Windows 7 and above. One side effect of this is that $OEM$ folders are no longer going to be copied, since that was something that SETUP.EXE did that the MDT LTIApply.wsf script doesn’t handle.
I’ve never been a big fan of using the $OEM$ folder structure, as it’s just as easy to add explicit XCOPY steps into the task sequence. But for those of you out there that are using them, you can leverage the attached script (see the attachment link below) in your task sequence to do that.
To set this up, first copy the script into your deployment share. Then, add a new step to the task sequence right after the “Install Operating System” step to run the script. It should look like this:
Now, it will follow the original MDT logic for locating the appropriate $OEM$ folder to use, checking in this order:
where %DeployRoot% is the path to the deployment share, %TaskSequenceID% is the ID of the running task sequence (e.g. WIN8), %SourcePath% is the path within the deployment share for the operating system being used, and %Architecture% is either X86 or X64, depending on the boot image being used. (That’s a bit of a flaw in the original MDT logic since we now support cross-platform deployments – it would choose an X86 $OEM$ folder even if you were deploying an X64 operating system. That’s probably a good sign that no one is using this option. Most people use the last one.)
Once it finds a folder, it will look for two folders in that $OEM$ folder and copy them to the appropriate place for the new OS:
The script doesn’t deal with any other folders because it’s too messy to do that from within Windows PE – drive letters aren’t the same as what they would end up being in the full OS.
I’ve talked with several people who have wanted to filter the list of items that are displayed in the Lite Touch wizard. Fortunately, that’s pretty simple to do as you can set the WizardSelectionProfile task sequence variable via CustomSettings.ini to specify the name of the selection profile that should be used to do the filtering: only the folders in the selection profile will be displayed for task sequences, applications, and language packs.
That works great if you want to do some simple rules-based filtering, e.g. use a different selection profile for each site. But let’s assume you want a different list of items for each task sequence (e.g. one list for Windows XP and another for Windows 7). It sounds simple enough by creating a rule that specifies:
WizardSelectionProfile=%TaskSequenceID%
If you try it though, you’ll find out that it doesn’t work. That’s because the TaskSequenceID variable hasn’t been set yet; CustomSettings.ini is processed before the wizard is displayed.
So to make this work requires a small script modification. If you look in the scripts folder of your deployment share, you’ll find a file named “DeployWiz_Initialization.vbs”. Search for the “IsThereAtLeastOneApplicationPresent” function. In that function, you’ll find this line:
oXMLAppList.sSelectionProfile = oEnvironment.Item("WizardSelectionProfile")
That’s what tells the wizard to filter the application list using the value specified in WizardSelectionProfile. Change that line to specify this instead:
oXMLAppList.sSelectionProfile = oEnvironment.Substitute("For %TaskSequenceID%") ' MODIFIED
This modified line assumes that you have created a selection profile for each task sequence. So if your task sequence ID was “WIN7” you would need a “For WIN7” selection profile.
If a selection profile with that name doesn’t exist, you’ll find that the list of applications is then completely empty. That’s because all the folders are going to be filtered out by this line:
set dXMLCollection = oXMLAppList.FindItems
So for safety, you might also want to add a little additional logic after that:
' INSERTED If dXMLCollection.count = 0 then oXMLAppList.sSelectionProfile = oEnvironment.Item("WizardSelectionProfile") Set dXMLCollection = oXMLAppList.FindItems End if ' END INSERTED
This logic basically falls back to the original WizardSelectionProfile name. And if that value is blank, it means “display all items and folders”.
Notice that I tagged the changed and inserted lines – those are really just comments to help identify the changes I have made to the standard MDT scripts. By tagging them, it makes it easier to find the changes that I need to reintegrate into my deployment share after upgrading MDT with a new update or hotfix.
There are a few operations in the MDT 2010 Deployment Workbench that can take a while. We’ve done our best to optimize those processes, but in many cases they will still take a good amount of time to complete. While you could certainly start an operation in one Deployment Workbench and then open another Deployment Workbench so that you can continue working, it would be even better to schedule these long-running tasks so that they run automatically, ideally when you are sleeping and when there aren’t any active Lite Touch deployments going on.
Fortunately, since the Deployment Workbench is now PowerShell-based you can now write simple PowerShell scripts to perform these activities. The following three samples show you how to do it.
The “Update Deployment Share” process takes the latest changes made to the deployment share (bootstrap.ini updates, new drivers, new patches, script changes, etc.) and updates the Windows PE boot images (WIM files and ISOs if requested). Depending on the extent of the changes, this process might take 15-30 minutes (depending on the I/O performance of the machine – it’s definitely an I/O-bound process, especially for the WIM and DISM actions performed by this process). The following script will automate the process:
Start-Transcript C:\Scripts\UpdateDeploymentShare.log # Connect to the deployment share Add-PSSnapIn Microsoft.BDD.PSSnapIn New-PSDrive DS002 MDTProvider \\MTN-SERVER\Distribution$ # Update the deployment share Update-MDTDeploymentShare -Path DS002: -Verbose Stop-Transcript
Start-Transcript C:\Scripts\UpdateDeploymentShare.log
# Connect to the deployment share Add-PSSnapIn Microsoft.BDD.PSSnapIn New-PSDrive DS002 MDTProvider \\MTN-SERVER\Distribution$
# Update the deployment share Update-MDTDeploymentShare -Path DS002: -Verbose
Stop-Transcript
Save that as “UpdateDeploymentShare.ps1” and schedule it to run nightly using the Windows Task Scheduler. The action command line required (assuming you saved the script in C:\Scripts) would be:
PowerShell.exe -File C:\Scripts\UpdateDeploymentShare.ps1
Make sure you have configured PowerShell to allow script execution, e.g. “Set-ExecutionPolicy RemoteSigned”. And be sure to update the deployment share path above, as I’m sure your deployment share isn’t at \\MTN-SERVER\Distribution$.
If you haven’t figured out where we moved “media deployment points” in MDT 2010, they now have their own node: look under the “Advanced Configuration” node in Deployment Workbench and you’ll see the new “Media” node. You can create one or more media definitions there, specifying what content should be included in the media (by specifying the selection profile to use when copying content to the media), Windows PE settings to use, whether to generate an ISO, etc.
The “Update Media Content” action is what actually does the work, copying the specified content, generating boot images, and (optionally) generating ISOs. The following script automates this process, looping through each of the media items that you have defined:
Start-Transcript C:\Scripts\UpdateMedia.log # Connect to the deployment share Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue New-PSDrive DS002 MDTProvider \\MTN-SERVER\Distribution$ # Process each of the media items Get-ChildItem DS002:\Media | % { Update-MDTMedia -Path "DS002:\Media\$($_.Name)" -Verbose } Stop-Transcript
Start-Transcript C:\Scripts\UpdateMedia.log
# Connect to the deployment share Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue New-PSDrive DS002 MDTProvider \\MTN-SERVER\Distribution$
# Process each of the media items Get-ChildItem DS002:\Media | % { Update-MDTMedia -Path "DS002:\Media\$($_.Name)" -Verbose }
Save that as “UpdateMedia.ps1” and schedule it to run nightly using the Windows Task Scheduler. The action command line to run this (assuming again that the script is saved in C:\Scripts) would be:
PowerShell.exe -File C:\Scripts\UpdateMedia.ps1
Again, be sure to edit the path above, as \\MTN-SERVER\Distribution$ is the path to my deployment share, not yours.
Network deployment points, now called linked deployment shares, also have a new home in MDT 2010 Deployment Workbench: look for them under “Advanced Configuration”, in the “Linked Deployment Shares” folder. These too use selection profiles to specify what content should be replicated, so arrange your folder structures as needed and create a selection profile that includes the required folders.
The “Replicate Content” action performs the actual replication, copying the content specified in the configured selection profile. It can also optionally generate the boot images for the linked deployment share (although if you want to configure the Windows PE settings for that remote deployment share you’ll need to open that deployment share in the Deployment Workbench to make the changes). The following script initiates the same process:
Start-Transcript C:\Scripts\UpdateLinkedDS.log # Connect to the deployment share Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue New-PSDrive DS002 MDTProvider \\MTN-SERVER\Distribution$ # Process each of the linked deployment share items Get-ChildItem "DS002:\Linked Deployment Shares" | % { Update-MDTLinkedDS -Path "DS002:\Linked Deployment Shares\$($_.Name)" -Verbose } Stop-Transcript
Start-Transcript C:\Scripts\UpdateLinkedDS.log
# Process each of the linked deployment share items Get-ChildItem "DS002:\Linked Deployment Shares" | % { Update-MDTLinkedDS -Path "DS002:\Linked Deployment Shares\$($_.Name)" -Verbose }
One last time: edit the path above to specify the path (either a local path or a UNC) to your deployment share. To run this using the Windows Task Schedule, specify an action command line like so:
PowerShell.exe -File C:\Scripts\UpdateLinkedDS.ps1
MDT 2012 includes a task sequence for deploying an operating system into a VHD, setting up the computer for booting from that VHD. See my previous blog posting about Deploy to VHD for more details on that. As I mentioned in that blog, setting up a differencing disk to be created during the “Deploy to VHD” task sequence doesn’t make sense, as the parent VHD would be empty. But it would be useful to be able to do it later, so that you have the already installed and configured OS in the main VHD, and then one or more differencing disks set up with that VHD as the parent.
So how do you actually do that? The basic steps would be:
To help with that process, I created a new script called Diff.wsf, attached below, that will perform all of those steps. Set up a new custom task sequence in your MDT deployment share that has a single step in it that runs the script like so:
Then reboot into your MDT Lite Touch boot image (either from media or from PXE) and run this task sequence. The command line parameters above tell it what to do:
The task sequence completes while in Windows PE, and as soon as you click finish on the summary wizard page, the computer will reboot into the new differencing disk, causing all changes to be written into the diff file while the parent VHD remains unchanged (and effectively read-only).
After that initial differencing disk has been created, the locally-staged script can be run directly without even using a task sequence. Assuming that the drive letter assigned to the physical disk containing the parent VHD (and the differencing disks) is D:, then the script will be located at D:\VHD\Scripts\Diff.wsf. When you run it from there (initiated from within the currently-running OS), you can specify any of the parameters described above, or you can leave off the parameters and the script will prompt.
Note that the script can’t actually delete the differencing disk that is presently in use because, well, it’s currently in use. But it can remove the BCD entry for it, and after a reboot it can then be deleted. So the script will also take care of cleaning up any “orphaned” differencing disks it finds laying around.
A few final comments on scenarios for running Diff.wsf from within the currently-running OS:
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)
Apparently I was so wrapped up in the MDT 2012 Update 1 development process that I forgot to talk about one of the areas that consumed weeks of my time before the MDT 2012 Update 1 release: improvements to the “Roles and Features” logic.
In MDT 2010 and MDT 2012, we had a task sequence action to “Install Roles and Features” that you could use to install roles and features on various operating systems. But it didn’t support Windows 8 or Windows Server 2012; it tried (unsuccessfully in some cases) to merge all of the role and feature lists into one single list for the rest of the OSes; it didn’t include a complete list of roles and features for all the OSes (e.g. Windows 7); etc. Basically, it needed a lot of work.
So in MDT 2012 Update 1, we took the opportunity to do some housecleaning. First, we changed the “Install Roles and Features” task sequence UI to allow you to display a filtered list of roles and features for the particular OS you are deploying:
We also made sure that the complete lists were present for all the various OSes: Windows 7, Windows 8, Windows Server 2008 (full install and core install), Windows Server 2008 R2 (full install and core install), and Windows Server 2012 (full install and core install). (We didn’t change the list for Windows XP and Windows Server 2003. Given that those are already in extended support and rapidly approaching their end-of-life date, we’re not adding new functionality for them.) And we verified the lists – something that gave our test team a real workout, as we had to make sure that we properly handled all the dependencies between the roles and features on OSes where that wasn’t handled automatically (e.g. Windows 7).
Then, we added a new Lite Touch wizard pane to let you dynamically choose roles and features. It automatically displays the right list based on the OS being deployed, allowing you to choose additional roles and features to install later in the task sequence:
What do you need to enable this wizard pane? Just add a step to the task sequence (somewhere in the State Restore phase; the exact location doesn’t matter, but I typically choose to put it in the “Custom Tasks” group) and the new pane will automatically show up. If you don’t want the wizard pane, you can turn it off through Custom Settings.ini by specifying “SkipRoles=YES”.
We also added a new “Uninstall Roles and Features” task sequence step that can be used to remove roles and features that you no longer want. It presents exactly the same list of roles and features inside the task sequence editor:
Notice the red box above, which I highlighted to point out one specific Windows 8 and Windows Server 2012 feature (and only shows up when you choose Windows 8 or Windows Server 2012): Not only can you uninstall roles and features, but you can also completely remove the components, getting rid of all the files related to that component. (If you ever want to add those back, Windows can download the components from Windows Update, or you can provide the original media to pull them from the WIM file. See http://technet.microsoft.com/en-us/library/hh824822.aspx for more details around this, as well as http://technet.microsoft.com/en-us/library/hh825020 for information about how to specify an alternate “repair source” instead of Windows Update.)
It’s worth noting too that we added some extra logic to handle the installation of .NET 3.5 on Windows 8 and Windows Server 2012. For both of these OSes, the .NET 3.5 feature is not present in the standard WIM file, but the files do exist on the media in the \sources\sxs folder. So for Lite Touch deployments, we will automatically provide these files to Windows as long as you have imported the full source files into your deployment share. For ConfigMgr clients, you would need to do a little bit more:
Behind the scenes, the script responsible for performing the role and feature work, ZTIOSRole.wsf, figures out the right thing to do for each OS:
Fun stuff. (For those of you keeping track, this also means that MDT now actually uses PowerShell itself during a deployment task sequence to install or uninstall roles and features on Windows Server 2008 R2 and Windows Server 2012. To keep things simple, the ZTIOSRole.wsf script calls the ZTIOSRolePS.ps1 script to take care of this. Look at the logic in ZTIOSRole.wsf and the new ZTIPSUtility.vbs script to see how that works, in case you ever have the need to do something similar, e.g. do some work in VBScript and some in PowerShell.)
Inside the new Windows Assessment and Deployment Kit (ADK) that was released back in August is a component called the Windows Performance Toolkit. I’ve talked about this at various events over the past few months, noting that you can use this kit to help identify what is causing your computers to take so long when they start up before they are usable. But people always ask “how do I do that myself”. First, I would suggest reviewing the documentation that is available online:
http://msdn.microsoft.com/en-us/library/hh162945
Some of you might have used a previous version of this toolkit, which included tools called XPERF and XPERFVIEW. This latest version includes new replacement tools (although the old tools are still around for compatibility, for those die-hard users) called the Windows Performance Recorder, WPR.EXE (command line) and WPRUI.EXE (GUI), and the Windows Performance Analyzer, WPA.EXE. The Recorder captures the events; the Analyzer displays the results. There is another utility called XBOOTMGR.EXE that takes care of one of the more complicated processes: setting up the computer so that it captures information at boot time. That’s the one we’ll want to use here.
So let’s assume that you are experiencing a problem with Windows 7 computers starting up slowly. You can reproduce this at will, but it’s not immediately obvious why. So you log on to the Windows 7 computer, install the Windows Performance Toolkit redistributable from a computer that has the ADK installed (so we don’t need to put the whole ADK on the Windows 7 computer), and then run the “xbootmgr.exe -trace boot” command to get everything started:
It will quickly reboot the computer, so be prepared. As soon as you can, log in to the computer to finish up the process. By default, it will wait two minutes to let the system settle down, but you can choose to end it sooner by clicking the “Finish” button:
Then you can run the Windows Performance Analyzer to look at the trace; start it using the shortcut on the Start menu. (Note that it requires .NET 4.0 so if you don’t have that installed it will complain. You can always analyze the trace remotely if you want, just copy off the *.ETL file.) Once it launches, have it open the trace file that was created in the same folder we ran XBOOTMGR.EXE from:
Since the Windows Performance Analyzer is very graphically-oriented, you might want to do this using a high-resolution display:
And that’s really where the fun starts: figuring out what graphs to add, what timeframes to focus on, and trying to get to a root cause. I’m no expert myself (yet), but I can see from the trace above that most of the time was spent in the Winlogon Init process. And probably not coincidentally, most of that time corresponds to the gpscript.exe and wscript.exe process lifetimes. And farther below, we can see generic events from Group Policy that confirm group policy processing took about a minute. So what was going on in this case? A bad startup script that took a minute to complete, combined with a policy setting that said “don’t run startup scripts asynchronously”.
Now I just need to teach myself how to better analyze these traces. Let the fun begin…
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.