In several articles and other works, I make the claim that backing up a Hyper-V host is largely a waste of time. A separate practice is to maintain templates and other offline images of systems for easy deployment of new systems. What these two topics have in common is the need (or at least the desire) to keep the images current with Windows patches. It doesn’t help much to save ten or fifteen minutes deploying Windows from a template or ISO if you then need to spend two hours installing updates. In the past, we would have use “slipstreamed” ISOs. That’s no longer possible with modern iterations of Windows. However, what we lack now is not the capability to update these systems, but the proper tools. Of course, if you’re willing (and able) to spend a lot of money on System Center, that suite can help you a great deal. For the rest of us, we have to resort to other options, usually homegrown.

To address that problem, I have crafted a script that will automatically update both VHDX files and WIM files. If you’re thinking that this doesn’t apply to you because you only deploy from physical media, think again! The issue of publicly-available Windows Server ISOs never being updated by Microsoft is the primary driver behind the creation of this script.

Script Features

Scripts to update WIMs and VHDs are numerous, so I’d like to take a few moments to enumerate the features in this script, especially the parts that set it apart from others that I’ve found.

  • Updates WIMs and VHDXs interchangeably
  • Updates multiple images with a single execution
  • Ability to scope updates; no more trying to apply Office 2013 patches to your Hyper-V Server image (unless that’s what you want to do; I’m not judging)
  • Subsequent runs against the same image will not try to re-apply previously installed updates
  • Designed to be run on a schedule, but can also be run interactively
  • Can update every image in a multi-pack WIM (if that’s what you want)


There are a few things that you’ll need to provide for this script to function.

  • A willingness to put away your DVDs
  • A USB flash device that is recognized on the physical systems that you use with a capacity of at least 8 GB (not applicable if you’re only here to update VHDXs)
  • An installation of Windows Server Update Services (WSUS)
  • Space to store WIMs and/or VHDXs (varies, but anywhere from 5 to 20GB per)
  • Spare space for the update operation (varies depending on the total size of all updates to be applied, but usually no more than a few gigabytes per operation)
  • On the system where you wish to run the script, the 2012 R2 or later Windows Server Update Services console must be installed. It includes the UpdateServices PowerShell module. For Windows 8.1+, download the Remote Server Administration Tools. I don’t believe that this module is available for Windows 7 or Server 2008 R2 or earlier, but it would be in the WSUS 3.0 SP2 download if it were. The following screenshot shows where the option appears on Windows 10. For Server, it is in the same location on the Features page of the Add Roles and Features wizard.
    WSUS in RSAT

    WSUS in RSAT


  • PowerShell 4.0 or later on the system that will run the script.

Something I want to make clear right from the beginning is that I don’t know how to update a Windows ISO image or use this to create an ISO image that can then be burned to DVD. I have moved to USB flash deployments for any physical systems where PXE is not an option. DVD has had its day but it will soon be following the floppy into the museum. If you haven’t tried loading an operating system from a USB stick, today is a great day to learn.

Deploying a Physical Machine from a WIM and a USB Stick

If you’re only going to be using this script to update VHDX files, skip this entire section.

You may not have realized it, especially if you’re like me and have been around since the pre-WIM days, but any time you use a Microsoft-pressed DVD or a burned ISO to install Windows, you are deploying from a WIM. Check your installation media’s file structure for a file named install.wim in the Sources folder. That’s where your Windows installation comes from. The trick is to get that WIM updated with the latest patches before using it again. There are a few inefficiencies with the method that I’ve discovered, but it works perfectly without requiring any paid tools.

  1. Acquire an ISO of the Windows, Windows Server, or Hyper-V Server operating system. If you only have physical media to work from and you don’t already have a tool, I use ImgBurn. It’s tough to get to through all the adwalls but it’s free and does the job.
  2. Acquire a copy of the Windows USB/DVD Download Tool.
  3. Insert your USB stick into the computer. If it’s not empty, whatever is on it will be destroyed.
  4. Run the tool that you downloaded. It’s still branded as “Windows 7” but it will work with whatever Windows ISO you give it.
    Windows 7 DVD Tool

    Windows 7 DVD Tool


  5. Browse to the ISO image from step 1 that you want to convert for USB.
    Windows USB Tool ISO Selection

    Windows USB Tool ISO Selection


  6. Choose USB Device.
    Windows USB Media Selection

    Windows USB Media Selection


  7. Ensure that the correct USB device from step 3 is selected. Press Begin Copying.
    Windows USB Select Output Drive

    Windows USB Select Output Drive


  8. You will get a small popup box warning you that your device will be erased. Click Erase USB Device. You’ll get yet another dialog telling you the essentially the same thing that the previous dialog said. I guess they really want to make certain that no one can say they didn’t know that their drive was going to be erased. Click Yes.
  9. Wait for the process to complete.
    Windows USB File Copy

    Windows USB File Copy


  10. When it’s finished, you can just close the window or click Start Over to craft another USB drive.
  11. Copy the sourcesinstall.wim from the USB device to a location where it can be updated — I prefer having it on my WSUS host. Because every single Windows media uses the name install.wim, I would either set up a folder structure that clearly indicates exactly where the file came from or I would rename the file.

You’re now ready to begin. The procedure going forward will be:

  1. Update the WIM.
  2. Copy the WIM back to the USB device.
  3. Use the USB device to install.

If you have more images than USB keys, that’s a workable problem. You can always rebuild the USB device from the ISO image and then copy over the latest copy of the WIM. However, now that you’ve come this far, I strongly recommend that you research deployment from a WDS server with WIM. It’s not that tough and it’s nice to never worry about installation media.

Script Usage

This script is slow. Very slow. The strongest control on speed is your hardware, but it’s still going to be slow. Part of the delay is scanning for applicable updates, so I’ve set that so that the scan of the WSUS server only occurs once per iteration, no matter how many VHDXs/WIMs you specify to update. To make it even better, it will record which updates were successfully applied to the WIM. As long as you don’t move or rename the log, additional runs will skip updates that have already been applied. This means that the first run against any given image will likely take hours, but subsequent runs might only require minutes.

You can run the script by hand, if you wish. If you only update any given Windows Server 2012 R2 one time, that will literally save you at least a years’ worth of updates each time that you deploy from it. My recommendation is to schedule the update to run once a month over the weekend so that you’re always up-to-date. To make that easier, I’ll show you how to build a supporting script to call this one with your images.

There are two parameter sets. One is to run against a single image file, the other is for multiple image files. Because of the way that WIMs work, you can’t just supply a list of file names. The parameter sets are otherwise identical.

Single Image File Parameter Set

Multiple Image File Parameter Set

There are only two required parameters: the image(s) and the WSUS system’s content folder. The hardest part is the image(s), so we’ll start there.

Specifying Image File(s)

The basic issue with specifying image files is that a single WIM can contain multiple images. If you’ve ever started an installation and been asked to choose between Standard and Datacenter and Standard Core and Datacenter Core or something similar, every single line that you see is a separate image in one WIM. When you update a WIM, you must select which image to work with. VHDX files, on the other hand, only have a single item so you don’t need to worry about specifying an index.

Specifying a Single VHDX

This is the easiest usage. Just use the full path of the VHDX with the WSUS content folder:

This assumes that you are running the script locally on the WSUS server.

Specifying a Single WIM

You must specify the index of an image within a WIM to update. If you don’t know, or just want to update all of them, specify -1. Updating every image will take a very long time!

If you’d like to narrow it down to a specific image but you don’t know what image to choose, you can interactively and locally run the script and you’ll be prompted:

WIM Index Menu

WIM Index Menu

This list is pulled directly from Get-WindowsImage. You can look at the available indexes yourself in advance with Get-WindowsImage D:FromISO2k12r2install.wim. If you do not specify -1 or a valid index when running Update-WindowsImage either from a scheduled task or in a remote PowerShell session, the script will fail.

Specifying Multiple Target Images

In order to update multiple images at once, you must supply an array of hash tables. If you’re new to PowerShell, take heart; it sounds much worse than it is.

First, make an empty array:

Then, make a hash table. This must have at least one component, a Path. For a WIM, it must also contain an Index. VHDX files can also have an index but they’ll be ignored.

Insert the hash table into the array:

Finally, submit your array to the script:

Easy, right? Now, let’s do a bunch in one shot:

Any image that can’t be found will simply be skipped. It will not impact the success or failure of the others.

Specifying the Target Product(s)

To reduce the amount of time spent attempting to apply patches, I added a filter for specific products. By default, the only scanned product is Windows Server 2012 R2 (which will include Hyper-V Server 2012 R2). You can specify what products to search for by using the TargetProduct parameter:

The items you enter here must match their names in WSUS verbatim or the updates will not be scanned (and there will be no error). To see that list, use Get-WsusProduct. Unfortunately, the PowerShell cmdlets for WSUS leave a great deal to be desired and there’s no simple way to narrow down which products that your host is receiving in synchronization.

Understanding how Available Updates will be Selected

I’ve never been the biggest fan of WSUS for a number of reasons, and you’re about to encounter one. I can easily determine if an update has been Approved in at least one place on the server and if it has been Declined in at least one place on the server. Finding out which computer groups that it has been Approved or Declined for is much harder. So, the default rule is: if an update has been approved on at least one group and has not been declined on any groups, it will be eligible. If you specify the IgnoreDeclinedStatus parameter, then the rule will change to: if an update has been approved on at least one group, it will be eligible. There is also a MinimumPatchAgeInDays parameter.

Other Parameters

Let’s step through the other, more self-explanatory parameters quickly:

  • WsusServerName: this is the name (short or FQDN) or the IP address of the WSUS server to connect to. If not specified, the cmdlet will assume WSUS is running locally.
  • WsusServerPort: the port that WSUS runs on. By default, this is 8530, because that’s the default WSUS port.
  • WsusUsesSSL: this is a switch parameter. Include it if your WSUS server is using SSL. Leave it off otherwise.
  • MinimumPatchAgeInDays: this is a numeric parameter that indicates the minimum number of days that a patch must have been on the WSUS server before it can be eligible for your images.
  • OfflineMountFolder: by default, the script will create an Offline folder on the system’s system drive (usually C:) for its working space. If this folder already exists, it must be empty. The folder is not removed at the end of the cycle. Use this parameter to override the name of the folder.

Scripting the Script

My vision is that you’ll set this script to run on a schedule. To work with multiple items, I’d make a script that calls the update script. So, save something like the following and call it every Friday at 7 PM:

Depending on your scripting skills, you could make this far more elaborate. Just remember that each image is going to take quite some time to update, especially on the first run.

The Script Source

As included here, you simply run the script on demand. If you’d like to dot-source it or use it in your profile, uncomment the function definition lines right after the help section and at the end. They are clearly marked.