Tutorial: Create and use a custom image for virtual machine scale sets with Azure PowerShell

When you create a scale set, you specify an image to be used when the VM instances are deployed. To reduce the number of tasks after VM instances are deployed, you can use a custom VM image. This custom VM image includes any required application installs or configurations. Any VM instances created in the scale set use the custom VM image and are ready to serve your application traffic. In this tutorial you learn how to:

  • Create and customize a VM
  • Deprovision and generalize the VM
  • Create a custom VM image from the source VM
  • Deploy a scale set that uses the custom VM image

If you don’t have an Azure subscription, create a free account before you begin.


This article has been updated to use the new Azure PowerShell Az module. You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. For Az module installation instructions, see Install Azure PowerShell.

Use Azure Cloud Shell

Azure hosts Azure Cloud Shell, an interactive shell environment that you can use through your browser. You can use either Bash or PowerShell with Cloud Shell to work with Azure services. You can use the Cloud Shell preinstalled commands to run the code in this article without having to install anything on your local environment.

To start Azure Cloud Shell:

Option Example/Link
Select Try It in the upper-right corner of a code block. Selecting Try It doesn't automatically copy the code to Cloud Shell. Example of Try It for Azure Cloud Shell
Go to https://shell.azure.com, or select the Launch Cloud Shell button to open Cloud Shell in your browser. Launch Cloud Shell in a new window
Select the Cloud Shell button on the top-right menu bar in the Azure portal. Cloud Shell button in the Azure portal

To run the code in this article in Azure Cloud Shell:

  1. Start Cloud Shell.

  2. Select the Copy button on a code block to copy the code.

  3. Paste the code into the Cloud Shell session by selecting Ctrl+Shift+V on Windows and Linux or by selecting Cmd+Shift+V on macOS.

  4. Select Enter to run the code.

Create and configure a source VM


This tutorial walks through the process of creating and using a generalized VM image. Creating a scale set from a specialized VHD is not supported.

First, create a resource group with New-AzResourceGroup, then create a VM with New-AzVM. This VM is then used as the source for a custom VM image. The following example creates a VM named myCustomVM in the resource group named myResourceGroup. When prompted, enter a username and password to be used as logon credentials for the VM:

# Create a resource a group
New-AzResourceGroup -Name "myResourceGroup" -Location "EastUS"

# Create a Windows Server 2016 Datacenter VM
New-AzVm `
  -ResourceGroupName "myResourceGroup" `
  -Name "myCustomVM" `
  -ImageName "Win2016Datacenter" `
  -OpenPorts 3389

To connect to your VM, list the public IP address with Get-AzPublicIpAddress as follows:

Get-AzPublicIpAddress -ResourceGroupName myResourceGroup | Select IpAddress

Create a remote connection with the VM. If you use the Azure Cloud Shell, perform this step from a local PowerShell prompt or Remote Desktop Client. Provide your own IP address from the previous command. When prompted, enter the credentials used when you created the VM in the first step:

mstsc /v:<IpAddress>

To customize your VM, let's install a basic web server. When the VM instance in the scale set would be deployed, it would then have all the required packages to run a web application. Open a local PowerShell prompt on the VM and install the IIS web server with Install-WindowsFeature as follows:

Install-WindowsFeature -name Web-Server -IncludeManagementTools

The final step to prepare your VM for use as a custom image is to generalize the VM. Sysprep removes all your personal account information and configurations, and resets the VM to a clean state for future deployments. For more information, see How to Use Sysprep: An Introduction.

To generalize the VM, run Sysprep and set the VM for an out-of-the-box experience. When finished, instruct Sysprep to shut down the VM:

C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /shutdown

The remote connection to the VM is automatically closed when Sysprep completes the process and the VM is shut down.

Create a custom VM image from the source VM

The source VM now customized with the IIS web server installed. Let's create the custom VM image to use with a scale set.

To create an image, the VM needs to be deallocated. Deallocate the VM with Stop-AzVm. Then, set the state of the VM as generalized with Set-AzVm so that the Azure platform knows the VM is ready for use a custom image. You can only create an image from a generalized VM:

Stop-AzVM -ResourceGroupName "myResourceGroup" -Name "myCustomVM" -Force
Set-AzVM -ResourceGroupName "myResourceGroup" -Name "myCustomVM" -Generalized

It may take a few minutes to deallocate and generalize the VM.

Now, create an image of the VM with New-AzImageConfig and New-AzImage. The following example creates an image named myImage from your VM:

# Get VM object
$vm = Get-AzVM -Name "myCustomVM" -ResourceGroupName "myResourceGroup"

# Create the VM image configuration based on the source VM
$image = New-AzImageConfig -Location "EastUS" -SourceVirtualMachineId $vm.ID 

# Create the custom VM image
New-AzImage -Image $image -ImageName "myImage" -ResourceGroupName "myResourceGroup"

Create a scale set from the custom VM image

Now create a scale set with New-AzVmss that uses the -ImageName parameter to define the custom VM image created in the previous step. To distribute traffic to the individual VM instances, a load balancer is also created. The load balancer includes rules to distribute traffic on TCP port 80, as well as allow remote desktop traffic on TCP port 3389 and PowerShell remoting on TCP port 5985. When prompted, provide your own desired administrative credentials for the VM instances in the scale set:

New-AzVmss `
  -ResourceGroupName "myResourceGroup" `
  -Location "EastUS" `
  -VMScaleSetName "myScaleSet" `
  -VirtualNetworkName "myVnet" `
  -SubnetName "mySubnet" `
  -PublicIpAddressName "myPublicIPAddress" `
  -LoadBalancerName "myLoadBalancer" `
  -UpgradePolicyMode "Automatic" `
  -ImageName "myImage"

It takes a few minutes to create and configure all the scale set resources and VMs.

Test your scale set

To see your scale set in action, get the public IP address of your load balancer with Get-AzPublicIpAddress as follows:

Get-AzPublicIpAddress `
  -ResourceGroupName "myResourceGroup" `
  -Name "myPublicIPAddress" | Select IpAddress

Type the public IP address into your web browser. The default IIS web page is displayed, as shown in the following example:

IIS running from custom VM image

Clean up resources

To remove your scale set and additional resources, delete the resource group and all its resources with Remove-AzResourceGroup. The -Force parameter confirms that you wish to delete the resources without an additional prompt to do so. The -AsJob parameter returns control to the prompt without waiting for the operation to complete.

Remove-AzResourceGroup -Name "myResourceGroup" -Force -AsJob

Next steps

In this tutorial, you learned how to create and use a custom VM image for your scale sets with Azure PowerShell:

  • Create and customize a VM
  • Deprovision and generalize the VM
  • Create a custom VM image
  • Deploy a scale set that uses the custom VM image

Advance to the next tutorial to learn how to deploy applications to your scale set.