Image Factory – Part 3: Save Custom Images and Distribute to Multiple Labs

This is the 3rd post in a series focused on leveraging DevTest labs to automate the creation of Custom Images in Azure.  Please refer to the 1st post for an overview of the solution, Introduction: Get VMs ready in minutes by setting up an image factory in Azure DevTest Labs and the 2nd post, Image Factory – Part 2! Setup VSTS and Factory Lab to Create VMs.

Today we will cover the steps needed to save the custom images from the already created Virtual Machines and then how to distribute these custom images to all the other DevTest Labs in the organization.  (Highlighted section in the diagram below)

Important note:  Any orchestration engine will work!  VSTS is not required, it’s just happens to be what we’re using for this blog series but the Image Factory is run using Azure PowerShell scripts, so it could be run manually, with Windows Task Scheduler, other CI/CD systems, etc.

Quick Review

If you’ve been following along with the prior posts, the following items should already be in place:

  • An Azure DevTest Lab for the Image Factory
  • A VSTS Project used to automate the image factory
  • Source code location containing the scripts and configuration (in our example, in the same VSTS Project used above)
  • build definition (in our VSTS example) to orchestrate the Azure Powershell tasks

If you’ve already gotten this far, it means you’re ready to save and distribute images!

Save the Virtual Machines as Generalized VHDs

The next step in the image factory is to save the existing Virtual Machines as generalized VHDs.  We have a script to do this just like our ‘create’ script!  The first step is to add another “Azure Powershell” task to the build definition as shown in the image below.

Once you have the new task in the list, click the item so we can fill in all the details!

Script Parameters

-DevTestLabName $(devTestLabName)

Generalized versus Specialized Custom Images

In the Azure Portal, when creating a custom image from a Virtual Machine we can choose to have a “Generalized” or “Specialized” custom image.

  • Specialized Custom Image: Sysprep/Deprovision was NOT run on the machine.  This means it is an exact copy of the OS Disk on the existing virtual machine (a snapshot).  The same files, applications, user accounts, computer name, etc., are all present when we create a new machine from this custom image.
  • Generalized Custom Image: Sysprep/Deprovision WAS run on the machine.  When this process runs, it removes user accounts, removes the computer name, strips out the user registry hives, etc., with the goal of generalizing the image so it can be re-customized when creating another virtual machine.  When you generalize a virtual machine (by running sysprep), the process destroys the current virtual machine – it will no longer be functional.

The script for snapping custom images in the Image Factory will save VHDs for any virtual machines created in the prior step (identified based on a tag on the resource in Azure).

Update Configuration for Distributing the Custom Images

The next step in the process is to push the custom images from the Image Factory lab out to any other labs that need them!  The core part of this process is the Labs.json configuration file.  You can find this file in the “Configuration” folder included in the Image Factory.

There are two key things listed in the Labs.json configuration file:

  • Uniquely identifying a specific destination DevTest Lab using the Subscription Id and the DevTest Lab name,
  • The specific set of images that should be pushed to the lab as relative paths to the configuration root. NOTE: you can specify entire folders (to get all the images in that folder) too

Here is an example Labs.json file with 2 labs listed, in this case we are distributing images to two different labs.

   "Labs": [
         "SubscriptionId": "<subscription ID that contains the lab>",
         "LabName": "<Name of the DevTest Lab>",
         "ImagePaths": [
         "SubscriptionId": "<subscription ID that contains the lab>",
         "LabName": "<Name of the DevTest Lab>",
         "ImagePaths": [

This is a good time to create an additional DevTest Lab to verify that the Image Factory is setup correctly.  This will be the destination Lab where the Image Factory will push images once they’re created.  All you need to do is create a lab and then update the Labs.json file with the Subscription Id and Lab Name in the appropriate spots.  NOTE:  If the lab is located in a different subscription than the Image Factory, please ensure that the Service Principle (used in the VSTS Service Endpoint) has access to the destination subscription.  Remember to check in the Labs.json file to VSTS once it’s updated!

Create the Distribute Images Build Task

Using the same steps as above, we need to add an additional “Azure Powershell” build task to our build definition.  Details on what to fill in are listed in the image below.  This task takes any custom images present in the Image Factory and pushes them out to any labs defined in the Labs.json file.

Script Parameters

-ConfigurationLocation $(System.DefaultWorkingDirectory)$(ConfigurationLocation) -SubscriptionId $(SubscriptionId) -DevTestLabName $(DevTestLabName) -maxConcurrentJobs 20

Verify it works - Queue the Build!

Once the distribution build task is complete, queue up a new build to make sure that everything is working!  After the build completes successfully, the new custom images will show up in the destination lab that was entered into the Labs.json configuration file.

Next Steps

the Image Factory based on Azure DevTest Labs is complete!  In the next post in the series, we’ll complete the Image Factory with a retention policy and cleanup steps.

Please let us know how we can continue to improve DevTest Labs by sharing your ideas and suggestions at the DevTest Labs feedback forum.

If you run into any problems with the features or have any questions, we are always ready to help you at our MSDN forum.


image Peter Hauge, Principle Software Engineer

Peter is part of the Visual Studio and .Net engineering team focused Visual Studio and Azure customers. He has been at Microsoft for 15 years, working on developer technologies throughout that time.

Comments (0)

Skip to main content