Customizing Your Windows Deployments

Hello again from Mall of America in Minneapolis Minnesota at the Minnesota Management Summit 2014 (MMS for short). #mmsminnesota

Today I am giving a presentation on “Customizing Your Windows Deployments – Tips, Tricks, and Code”.


Stick with Well-Known and Proven Solutions
MDT Wizard Studio


I wanted share the source code examples from my presentation:

MMS2014 – Customizing Your Windows

Inside you will find the following:

MMS2014 - Customizing Your Windows Deployments.pptx
1 - Unattend\makevhdx.ps1
1 - Unattend\make_client_vhd.cmd
1 - Unattend\Run-VHD.ps1
1 - Unattend\unattend.Workgroup.xml
1 - Unattend\unattend.xml
2 - ztigather\CustomSettings.ini
2 - ztigather\UserExit.vbs
3 - CMD\AppWrapper.cmd
3 - CMD\Source\7z925x64.msi
4 - VBS\ZTIUtility.vbs
5 - PS1\CM1.CleanUp.ps1
5 - PS1\Get-Service.ps1
5 - PS1\Test-MDTPowerShell.cmd
5 - PS1\Test-MDTPowershell.ps1

In the “1 – Unattend” folder is my example of how to take a Windows *.iso image and mount in Hyper-V.
In the “2 – ZTIGather” folder is a quick example of a customsettings.ini file and a userexit.vbs script.
In the “3 – CMD” folder is an example of using a CMD file to wrap commands in a batch script.
In the “4 – VBS” folder I have some examples on how to create MDT VBScript files.
In the “5 – PS1” folder I have an example of how to call a powershell script from within MDT.


Imaging Factory performance

I’ve been experimenting recently with building a Hydration Imaging Factory on one of my servers. A Hydration Factory is a Windows Host that constructs Windows images for use in deployment.

Perhaps you have a simple setup in your environment using MDT LiteTouch. This could be something like a task sequence that installs Windows 7 x64, runs Windows Update, syspreps and captures back to a *.wim file. Or perhaps you have a laundry list of applications that need to be installed in your corporate standardized image for VDI scenarios. With the correct settings in your CustomSettings.ini file, this process could be fully automated, and repeatable. Spin up a Virutal Machine and 30 minutes later you have a new install.wim file.

A Hydration Imaging Factory will combine the automation of MDT LiteTouch with some PowerShell automation to build out a list of virtual machines.


I’ve been spending some time trying to make my Hydration Factory system modular, and right now I can kick off a new build and my Host.
In my system:

  • All images are fully patched and have IE 11 and the KMDF
  • Some images are “Min” – No applications, just Updated/Patched
  • Some images are “Full” – Applications like Adobe Reader, Chrome, VCRT, etc.
  • I also create a Hyper-V specific versions (PersistAllDeviceInstalls)
  • I have packages for Office and SQL, but did not include below
  • I run a dism /clean command just before sysprep to trim the images
  • Results

    Given my host test machine (Simple single processor multi-core desktop, i7, 32GB of ram, and multiple SSD Drives). It took about 7 hours to build out the following Virtual Machines.

    4,080,851,813 WIN10STPX64.SRV.Full.HV.WIM
    4,080,982,651 WIN10STPX64.SRV.Full.WIM
    3,954,997,709 WIN10STPX64.SRV.Min.Core.HV.WIM
    3,955,009,907 WIN10STPX64.SRV.Min.Core.WIM
    3,955,336,881 WIN10STPX64.SRV.Min.HV.WIM
    3,955,175,443 WIN10STPX64.SRV.Min.WIM
    3,882,925,692 WIN10TPX64.ENT.Full.HV.WIM
    3,882,213,922 WIN10TPX64.ENT.Full.WIM
    3,754,245,946 WIN10TPX64.ENT.Min.HV.WIM
    3,754,582,199 WIN10TPX64.ENT.Min.WIM
    2,989,545,883 WIN10TPX86.ENT.Full.HV.WIM
    2,992,590,857 WIN10TPX86.ENT.Full.WIM
    2,921,467,219 WIN10TPX86.ENT.Min.HV.WIM
    2,921,762,549 WIN10TPX86.ENT.Min.WIM
    5,775,824,112 WIN2008R2SP1.Full.HV.WIM
    5,775,798,368 WIN2008R2SP1.Full.WIM
    4,618,522,652 WIN2008R2SP1.Min.HV.WIM
    4,618,521,668 WIN2008R2SP1.Min.WIM
    4,921,167,148 WIN2012R2U.Full.HV.WIM
    4,921,555,872 WIN2012R2U.Full.WIM
    4,513,623,325 WIN2012R2U.Min.Core.HV.WIM
    4,554,749,492 WIN2012R2U.Min.Core.WIM
    4,451,558,474 WIN2012R2U.Min.HV.WIM
    4,459,989,734 WIN2012R2U.Min.WIM
    5,955,716,470 WIN7SP1X64EVAL.Full.HV.WIM
    5,751,198,710 WIN7SP1X64EVAL.Full.WIM
    4,761,940,473 WIN7SP1X64EVAL.Min.HV.WIM
    4,776,248,329 WIN7SP1X64EVAL.Min.WIM
    4,223,192,736 WIN7SP1X86EVAL.Full.HV.WIM
    4,179,078,039 WIN7SP1X86EVAL.Full.WIM
    3,440,522,203 WIN7SP1X86EVAL.Min.HV.WIM
    3,440,523,165 WIN7SP1X86EVAL.Min.WIM
    5,443,684,448 WIN81UX64EVAL.Full.HV.WIM
    5,442,443,606 WIN81UX64EVAL.Full.WIM
    4,723,143,084 WIN81UX64EVAL.Min.HV.WIM
    4,722,734,367 WIN81UX64EVAL.Min.WIM
    4,278,679,489 WIN81UX86EVAL.Full.HV.WIM
    4,277,099,032 WIN81UX86EVAL.Full.WIM
    3,648,938,088 WIN81UX86EVAL.Min.HV.WIM
    3,650,404,303 WIN81UX86EVAL.Min.WIM
    40 File(s) 172,408,546,058 bytes

    Post Processing

    I have scripts to merge similar install wims together to save space. This is similar to what Microsoft does with the Windows Release DVD’s, putting multiple SKU’s in the same *.wim file.

    4,298,516,365 WIN10STPX64.SRV.wim
    4,053,529,276 WIN10TPX64.ENT.wim
    3,138,798,185 WIN10TPX86.ENT.wim
    6,750,236,116 WIN2008R2SP1.wim
    5,292,634,524 WIN2012R2U.wim
    6,785,580,325 WIN7SP1X64EVAL.wim
    5,080,754,294 WIN7SP1X86EVAL.wim
    6,067,072,626 WIN81UX64EVAL.wim
    4,684,309,077 WIN81UX86EVAL.wim
    9 File(s) 46,151,430,788 bytes

    Additionally, I tried out Johan’s Beyond Zip method to shrink files down even more…

    23,190,306,816 CapturePackage.vhdx

    From 160GB down to 21.6GB, an savings of about 87% Wow!

    Finally, I have other scripts to convert the *.wim images to *.vhdx files for easy import into Hyper-V or Azure. See my last post on persistalldeviceinstalls


    As a service, I’ve been thinking of uploading my updated/patched images for these Operating Systems (and more) to a public internet file sharing site like my OneDrive for Business account. Rebuilding everything from scratch every Patch Tuesday. One drive for business has 1TB for use, I could share the images, how cool would that be?

    First glitch is that OneDrive for Business still has the 2GB file limitation, so that would require splitting the files up into 2047MB chunks and reassembling later.

    However, my biggest problem right now is my ISP connection. Today, I was averaging about 11.14Mbps upload speed to OneDrive. To upload 42GB of Wim files to OneDrive for Business would take more than 8 hours, which is more time than it took to build the images in the first place. That combined with my ISP’s data caps, makes sharing this from my current office cost prohibitive.


    Let me know if you are interested in setting up your own imaging factory environment. I’ve already done this for a large Video Chipset Mfg. And I can customize for your needs.

    PersistAllDeviceInstalls in Hyper-V Environments

    I’ve been creating some images for virtual machine environments.

    One of the goals of sysprep is to take all the elements that make an operating system specific to a machine, and make it generic for other machines. However if you know that the hardware is the same, you can tell Sysprep not to strip out the installed device drivers and keep them for the next machine.

    There are two ways to persist the devices and drivers when calling sysprep. If you are using Windows 8 or greater, you can add the /Mode:VM switch to the end of the sysprep call. However if you want the process to work in Windows 7 or Windows Server 2008 R2, you need to put the PersistAllDeviceInstalls element in an unattend.xml file and pass that through to sysprep.

    I created an unattend.xml file and placed it in my MDT Litetouch deployment share under the Tools directory.

    This particular unattend.xml file is crafted to work for both x86 and x64 platforms.

    <?xml version="1.0" encoding="utf-8"?>
     <settings pass="generalize">

    Within MDT LiteTouch I then can then set my CustomSettings.ini file to:



    After building out some of my virtual machines, I decided to run some performance tests against the images that got the PersistAllDeviceInstalls, and those that did not.

    I have a script that will convert a *.wim to a *.vhdx file, and inject a custom unattend.xml file. Import the *.vhdx file into a virtual machine and start up.

    For the image that was given PersistAllDeviceInstalls, it took 1 minute 20 seconds from the start of the virtual machine to the logon prompt.

    For the normal image without PersistAllDeviceInstalls, it took about 3 minutes from the start of the virtual machine to the logon prompt.

    That cut our install time down by almost HALF! Pretty cool!


    Next up, playing around with the VDI optimization scripts from Jeff and Carl

    My Server of Choice for 2014

    I posted some server specs today for one of my servers (yes I have more than one), and it got some attention. Really it’s not my best server.

    My reference server of choice this year is my SuperMicro box:


    * SUPERMICRO SYS-5038D-I Mid-Tower Server
    * 32GB Crucial 240-Pin DDR3 SDRAM ECC Buffered Ram
    * Intel Intel Xeon E3-1270V3 Haswell 3.5GHz
    * Seagate Barracuda ST2000DM001 2TB 7200 RPM
    * (2x) SAMSUNG 840 EVO 250GB SATA Drives

    I load it up with Windows Server 2012 R2 Server (eval) for testing, and it runs like a dream!

    I use 1 SSD drive for the OS, and the other for holding most of my virtual machines.

    Right now I have about 13-15 Virtual Machines up and running with the Windows 8.1 Enterprise Management Suite. No Problem!


    And it’s only using about 55% of the available memory!

    Whole package should be less than $1500 on Newegg.

    Do you have a better configuration for hosting 10-15 Virtual Machines? let me know!

    Update: Forgot to mention my best server:

    The best server I ever had was at Microsoft when I worked in the extended “System Center” group

    HP Z800
    * 96GB of ECC Ram
    * (2x) Intel Xeon E5640 (if I recall) processors (each with 4 cores)
    * (4x) 300GB Seagate 15k SAS drives ( yes 15000 RPM’s )

    The most obscene part was that I had (TWO) of these machines. I will miss them. :^(


    Together they would cost about as much as I paid for my last car.

    Checking for tablets in MDT

    Quick Post:

    How do you test for tablets in MDT?

    Create a new step in your Task Sequence, like “Set Task Sequence Variable” –> IsTablet = True

    Then, in the “Options” tab, add a new “WMI Query” with the following:
    (One Line)

    SELECT * FROM Win32_ComputerSystem 
    WHERE PCSystemType = 2 and PCSystemTypeEx = 8

    This condition appears to correctly identify tablets vs non-tablets. My Lenovo W530 (not tablet), my Surface Pro (IsTablet), and my Dell Venue 8 Pro (is Tablet), and a Virtual Machine (not tablet).

    Hopefully Microsoft will update their documentation, PCSystemTypeEx does not appear in the standard MSDN documentation.

    Image Factory Automation

    One area where MDT Litetouch excels is with Image Creation. I know of several groups within Microsoft (including Microsoft Consulting) who recommend using MDT LiteTouch to create images, even if those images are eventually used within SCCM OSD (Operating System Deployment).


    Back in the Windows XP days, the OS came with it’s own proprietary installation system. Say you spent some time getting XP updated to the latest Service Pack, along with all the necessary security updates, and the latest version of Office. You might want to take a snapshot (or checkpoint) of this reference disk (Image) to reload on other machines. That’s where Sysprep and 3rd party products like Ghost came to the picture.

    Starting with Windows Vista, Microsoft started distributing the OS using a new file archival format: Windows Imaging Format (*.wim files). *.wim files are compressed archives with space to store extra metadata. It’s also intelligent to hold multiple archive sets within a single *.wim file, and only keep a single instance of the same file, so a single wim file can hold Windows Starter, Home Premium, and Ultimate on the same disk!

    The main difference between Ghost (*.gho) files, and WIM (*.wim) files is that Ghost Files store the contents of a hard disk in block format (partitions and all), whereas the WIM files are stored as files. That means that when you apply a *.gho file to a disk of different size, Ghost itself needs to do some resizing of the partitions to make it fit. Whereas the *.wim file can only hold those files and streams it knows about (boot sectors and deleted files are ignored).

    One of the coolest features of *.wim files is that Microsoft allows customers the ability to capture the contents of a Drive (volume) into your own *.wim file. In fact for some versions of Windows, you can replace the install.wim file on the Install DVD with your own captured *.wim file, and continue with the installation process like it came from Microsoft.


    So how do you create your own image for use?

    • First off, you should setup a machine *just* the way you want it.
      Install the OS, Install Apps, Configure Settings, Add drivers if necessary.
    • Next, run Sysprep on the machine. This will prepare the machine to re-run OOBE Setup.
    • Finally, boot into WinPE and capture the image using imagex.exe or dism.exe into a *.wim file.

    Of course this is a major oversimplification of a complex process. For example, adding Drivers to the image depends on the scenario. If you *know* for certain that this image will only be applied against a single kind of computer system you could perform the capture on that reference system so that the image contains all necessary drivers, ready to go. Otherwise, if you are targeting several kinds of hardware, I would strongly recommend using Hyper-V Virtual Machines to create your images, since the OS won’t load any extra drivers into the image.

    Enter MDT LiteTouch

    The MDT LiteTouch Client and Server deploy Task sequences were designed from the start to handle the full deployment installation process. OS installation, Application Installation, Sysprep and Capture, all from the default Client and Server Task Sequence templates.

    One of the cool things to do is to make the LiteTouch process into a Fully automated No-Touch process (we reserve the ZeroTouch name for SCCM with MDT extensions :^).

    Let’s start off with a Deployment Share setup specifically for image creation in our lab. To automate the process I have created an account on the local machine that has read/write permissions on the Deployment Share but is *not* a member of the local users group. I have also given it a random password.

    In our Bootstrap.ini file, we add four lines to the bottom:


    This will allow us to skip over the MDT LiteTouch Welcome Wizard, and connect directly to the Deployment Share.

    I have created a virtual Machine used to capture Windows 8.1 x64 images, I booted up the machine and found out it’s machine BIOS GUID (check the bdd.log file), and in this case the GUID is: {29c80ff5-4dc4-4497-a035-472118542fd7}. Some people use the MAC address of the virtual machine.

    IN our CustomSettings.ini file, in addition to the standard settings used by our regular deployments, I have added the following entries:

    DoCapture = YES
    ComputerBackupLocation = %DeployRoot%\Captures
    BackupFile = %TaskSequenceID%.wim

    First off I have changed the [Settings]Priority to add UUID. This means that the first thing processed in the CS.ini file will be the matching GUID section found in the file (if any). Within my GUID Section, I have created an application bundle to install my preferred applications set, Defined the settings to capture the machine back to the imaging server, and set everything else to full automation.

    As one last trick, I take a Snapshot/Checkpoint of my Virtual Machine so that I can roll back the machine and restart this *automated* imaging process from scratch. This can be great for Patch Tuesday, just roll back and re-image. The only work on my part is to kick off the imaging, and review the logs when finished.


    What about SCCM you ask? SCCM OSD (with MDT integration) has the same ability to install an OS, Applications, Sysprep, and Capture. Why not use that system?

    Well, if you have a fully functional SCCM OSD deployment system ready, along with all the applications pre-packages, then yes, it may be a good idea to continue using SCCM OSD to create your images. However… if you do not have a fully functional system ready with all of your applications packaged (fully automated). I would not recommend starting with LiteTouch instead.

    Running in the Administrator context in MDT LiteTouch allows us more leeway when building our images with unproven systems and components. We can see what’s being installed, see error messages on the screen, and debug in real time on the console. There is just no need to install the overhead of SCCM for a small contained process like imaging creation if you have not already automated everything in SCCM.


    Now there is an important point to make here. If we can Automate as much as possible in the imaging process, typically the installation of our Applications, we can rebuild our core images over and over again with little efforts.

    Of course there are some scenarios where Component “X” is difficult to install in a fully automated fashion (or we don’t know how to install). Some times we can *RePackage* the application using some 3rd party tool, or perhaps we can push the installation of this application to another process, perhaps during OS deployment, rather than during Image Creation. MDT LiteTouch also has a “Manual” step that can be added to the Task Sequence to allow an Imaging team to perform non-automated steps.

    However, for the most part, my recommendation (and the recommendation from many at Microsoft) is that if you can automate the installation of applications, you should. As you can now leverage no-touch image building.

    Image Factories

    Once you have some of the basic settings defined for creating your image, the next step would be to automate the whole thing with PowerShell.

    We can use PowerShell to Create User Accounts, Create Virtual Machines, Assign Network Switches, Apply our the LitetouchPE_x86.iso, and start. We can also use PowerShell to inject our No-Touch settings from above dynamically into the MDT Process.

    While working for Microsoft’s own IT department, we would create multiple images at once, each for a different use ( Windows 7, Windows 8, Windows Server 2008 R2, Windows Server 2012, With *and* without Office ). Why would we provide an image *without* Office? Well, there are groups within Microsoft who don’t want Office, they are developing and DogFooding the *next* version of office :^).

    We call this whole system an “Image Factory”. There are a lot of moving parts, but when done properly, rebuilding your image set for patch Tuesday is no problem.

    Server Host Provisioning for Windows Server 2012 R2 (RTM)

    New Tool: Server host provisioning for Windows Server 2012 R2 (RTM)

    This is the full RTM release of the Server Host Provisioning tool I created for Server 2012 R2 *Preview*.

    The goal of this tool is to provide “The Quickest and easiest way to install Windows Server 2012 R2 on a Physical Host machine using a USB Drive“. That USB drive is created in an automated fashion with this Server Host Provisioning kit. Note that this tool is not designed to install Windows Server within Virtual Machines, instead it’s all about the physical Host.


    I’ve created a quick video that goes through the entire kit build process, it only takes about 10 minutes (longer with narration):

    New Features:

    • The tool will auto install the “Eval” version of Windows Server 2012 R2, however there is a new option to change the SKU from Eval to Volume Licensing (See Here) Great if you have Full KMS server.
    • There is the option to install the Windows 8.1 ADK and MDT 2013 on the Host.

    Here’s what the App screen looks like:


    Some Notes:

    • Your build machine must be running Windows 7, Windows Server 2008 R2 or greater.
    • You must have .NET Framework 3.51 installed on the local build machine
    • This tool will automatically install MDT 2013 and Windows ADK 8.1. Previous versions must be manualy removed before running this tool.
    • If you are running on Windows 7 or Windows 2008 R2, and do not have the Windows Server 2012 R2 OS Eval bits extracted locally, this tool will automatically install 7-zip from to extract the *.iso.
    • This tool will automatically mark any USB drive attached as “active”, however it is recomended to re-format the drive as FAT32 again if you are running on Windows Sever 2008 R2 or above. This tool will not reformat the drive as a safety measure.
    • This tool is designed to use the Windows Server 2012 R2 “Eval” version by default, and will be downloaded automatically from You may specify a local path to the OS installation files to bypass the default download behaviour. This is helpful if you have a limited network connection and aleady have the bits locally.


    Let me know if you find this tool helpful.


    The program is located here: