Automating MDT Windows 10 Image Captures with Packer

So to be up front, this is not a tutorial for setting up Packer to capture images to MDT, it is more of a postmortem on my experience doing so. There was a lot of trial and error involved in this, and my memory sucks so the exact steps involved are not here. If you want to do it, I recommend cloning Stefan’s Git repo first, and then modify to what you need. That is what I did.

With the new deployment model of Windows 10, IT professionals need to change the way they handle the deployment of operating systems. Every six months, there is a new OS coming out for Windows 10. The days of setting up a process of deploying a Windows OS and letting it go for a few years are over. If you are deploying Windows 10 to workstations in the enterprise, time to change your game.

When I deploy an OS, I want it to be the most current and with any OS updates installed already. Obviously, the alternative is installing updates after initial OS deployment, which is time consuming. Add in the fact that I need to have a new OS set up every six months, and the need to automate this process is now essential because I absolutely despise redundant work.

For deployment of a Windows OS, I still use MDT. It is still probably the best free tool to do this. The problem with MDT, is that its hardly infrastructure as code material. Almost impossible to use without the GUI. Although there are ways to automate it make capturing and deploying unattended. I like unattended. It means I can drink coffee or shit post on Twitter while automating is happening all around me.

So for me MDT is a required tool at the moment, which means I need something that can orchestrate capturing a reference image along with MDT. There are tools for this, namely Mikael Nystrom‘s Image factory. Image factory seems like an awesome tool, but I wanted to explore other options. That is when I came across Hashicorp’s Packer. First, I am a Hashicorp fanboy. I haven’t used a lot of their tools, but I freaking love Vagrant so I figured it would work well, I believe I was right.

Packer was created for automating the creation of machine images, mostly for immutable servers for the cloud. Packer takes in an ISO, builds out the image, provisions software and then sends it “packing” for post processing. The end result is typically an image(s) for AWS, Google, VMware or Vagrant (among others).

So my idea was to do the following basic workflow:

  • Take a Windows 10 ISO
  • Build a reference image using Packer and Virtualbox
  • Capture it with MDT
  • Change my MDT production Task Sequences to use the new captured reference image

All of this I want basically automated, all I want to do is pass the ISO as an argument to something and have it to the rest. I decided that the easiest way for me to do this was to create a little PowerShell wrapper function around Packer and MDT to do this.

Like just about every other DevOps tool in the wild, Packer was really built for Linux. The support for Windows is growing, but still has work to do. In the Packer/Windows area there are two Github repos you will want to look at:

For my purposes, I ended up using Stefan’s Windows 10 template and changing it a bit. His autounattend.xml file worked well. The biggest hangups I had during this process was not so much with Packer, but with Windows 10 and MDT.

MDT Setup

I created an MDT deployment share for capturing the image called “WIN10CAPTURE$”. In it I configured my bootstrap and customsettings INI files to automate all of the capturing to the point where all I have to do is kick off the litetouch.vbs from my reference VM and the rest just works. The Task sequence I used was for “Capture only”, with no modifications.

CustomSettings.ini:

Bootstrap.ini:

My other MDT share is for production deployment of Windows 10, simply called “MDT”. This is where my captured WIM file will be imported to.

Packer Setup

There are three main files I worked with from Stefan’s Git repo. The windows_10.json (Packer template) and autounattend.xml. The other file I added was MDT.ps1 which just starts litetouch.vbs from my MDT Capture share. In Packer, if you want to spit out an artifact from your build you will likely use a post-processor, for instance creating a Vagrant box. The problem I have is that there is no MDT post-processor, or even a PowerShell post-processor, so I have to just use a provisioner instead that starts litetouch.vbs for the capture (MDT.ps1). This is fine since both provisioners and post-processors are optional in Packer, but it feels like a hack of sorts. The other problem I ran into (which I still do not fully understand) is that when I enabled installing Windows updates in autounattend, Packer would stop the MDT capture after the first reboot. If I did not install updates, it let it go until the capture was compete. To get around this, I added another provisioner that just waited 30 minutes before Packer ultimately destroys the VM, which in my environment was enough for the MDT capture to complete.

My windows_10.json:

My autounattend.xml which I made the followed changes to:

  • Product key
  • User account and password
  • Changed OS name to “Windows 10 Enterprise”

My MDT.ps1 which is used to kick off litetouch.vbs:

Invoke-PackerMDTCapture function

Finally, I needed a method to wrap Packer along with some additional PowerShell code that would change my MDT production task sequence to any new captured images. For this, I turned to PowerShell.

As you will see in my function, I added some default parameter values for making it easy to re-run since I had to test this a lot. So the function basically does this:

  • Get the hash of a Windows 10 ISO
  • Change location to Packer root path
  • Run packer build with ISO, hash, checksum type and JSON template
    • Creates virtualbox VM
    • Uses Windows 10 ISO and autounattend to build machine
  • Once build is complete check the status of the MDT capture
  • If MDT capture was successful, move on. If not, halt
  • Invoke-Command into MDT server
    • Add MDT PSSnapin
    • Add PSDrive for MDT
    • Get the captured WIM based on last write
    • Import the captured WIM into the production MDT share
    • Gets the WIM GUID to be used in changing the task sequences
    • For each task sequence, change to the new captured WIM
    • Update the Production MDT Share

Lets run it!

So I stated before, most of my parameters for Invoke-MDTCapture as in my function so that I dont have to specify them each time not to mention they would make this blog unreadable.

The only one I specify is -Credential for remoting into my MDT server.

Now the fun happens…

 

 

The end result is a new Windows 10 OS with all OS updates installed, ready for deployment with MDT. Keep in mind, there is a lot more you can in terms of modifying your reference image before capturing it such as installing software and changing default profile settings, but for the purposes of this post I wanted to keep it simple.

Going forward

Ideally when a new major build of Windows 10 or 2016 is released, I want to just pass the ISO to Invoke-PackerMDTCapture and let the rest of my setup to its thing. I know that probably wont be that simple because it seems Microsoft loves changing the crap needed in autoattend.xml to automate that as I soon found out when troubleshooting. Not to mention who knows what may or may not break sysprep. I do think this at least will make it a smoother experience for me.

Leave a Reply

Your email address will not be published. Required fields are marked *