Learn how to work with images in PowerShell in this article by Thomas Mitchell, a 25+ year veteran of the IT industry with an in-depth skill set that spans numerous IT disciplines.
Welcome to Working with Images!
We’re going to take a look at some image-centric tasks and commands that you should know how to handle as part of your day-to-day operations. This article will help you to deploy virtual machines from images in the Marketplace and also how to deploy virtual machines with custom images.
Working with Marketplace Images
Although a virtual machine can be deployed in Azure with default options, the Azure marketplace offers numerous virtual machine images that can be used to create a new virtual machine. You need to deploy a virtual machine, called MyVM
, using the default Windows Server 2016-Datacenter image. Here, you’ll learn how to use PowerShell to search the marketplace for other Windows images and how to deploy a new virtual machine in Azure using one of those images.
Creating a resource group
Before deploying a VM in Azure with PowerShell, you need to first create a resource group into which the VM will be deployed. An Azure resource group, by the way, is a logical container into which Azure resources are deployed and from where they are managed. Deploying a resource group is rather easy; it is completed with just a single PowerShell command.
To provision a group, you just need to run the New-AzureRMResourceGroup
command. When running the command, you need to specify a name for the resource group and a location for it:
New-AzureRmResourceGroup -ResourceGroupName "VMLab" -Location "EastUS"
The preceding command creates a resource group called VMLab
and it creates it in the EastUS
location:
Running the New-AzureRMResourceGroup
command takes just a moment or two and, once the command completes, you can visit the Azure dashboard to confirm that the resource group has been created. Instead, you can run the Get-AzureRmResourceGroup
PowerShell command without any switches, to ensure that the new resource group is listed.
To confirm that your new VMLab
resource group has been created, run the following command:
Get-AzureRmResourceGroup
Upon running the preceding command, you should see a resource group called VMLab
listed.
Key PowerShell commands
The process of deploying a virtual machine using a specific image includes finding a publisher, finding an offer from that publisher, and then locating an SKUfor the image to use.
To work through this process, you need to run three different PowerShell commands:
-
Get-AzureRmVMImagePublisher: This command returns a list of image publishers.
-
Get-AzureRmVMImageOffer: This command returns a list of image offers from a specific publisher.
-
Get-AzureRmVMImageSku: This command will filter on the publisher and offer name to return a list of available image names.
The process seems, on the surface, a bit unwieldy, but it’s not terribly difficult. Once you’ve done it a few times, it really doesbecome second nature:
- To track down an image to deploy from, launch a PowerShell session, connect to the Azure tenant, and use the following commands, starting with the
Get-AzureRmVMImagePublisher
command:
Get-AzureRmVMImagePublisher -Location "EastUS"
As you can see in the following screenshot, the preceding command returns a list of publishers available in the EastUS
location. If you are following along, make sure MicrosoftWindowsServer
is listed, since this is the publisher that provides Windows OS images on the marketplace. The following screenshot shows all publishers in the EastUS location:
- After ensuring that
MicrosoftWindowsServer
is listed, run theGet-AzureRmVMImageOffer
command to see what image offers are available in theEastUS
location from theMicrosoftWindowsServer
publisher:
Get-AzureRmVMImageOffer `
-Location "EastUS" `
-PublisherName MicrosoftWindowsServer
There are three MicrosoftWindowsServer
offers available in EastUS. To deploy a Windows virtual machine, you’ll want to ensure WindowsServer
is one of the choices available. The following screenshot shows the available image offers from the MicrosoftWindowsServer
publisher in the EastUS
location:
-
- Track down available image names within the
WindowsServer
offer, using theGet-AzureRmVMImageSKU
command:
Get-AzureRmVMImageSku `
-Location "EastUS" `
-PublisherName "MicrosoftWindowsServer" `
-Offer "WindowsServer"
Running the preceding command returns quite a few options. Keep in mind that the list you see (if you are following along) is filtered, based on the specified Publisher and Image Offer. For this exercise, you’ll want to ultimately choose the
2016-Datacenter
option—since that is the OS we are going to deploy in this exercise. In the following screenshot, you can see the many different SKUs that are available through theWindowsServer
offer from theMicrosoftWindowsServer
publisher: - Track down available image names within the
Now that you know which publisher you are using, which offer you will need, and which image you are going to deploy from, you can deploy a virtual machine using your chosen image.
Provisioning a new virtual machine from a specific image
In the previous section, we decided we would use the 2016-Datacenter
image for a new virtual machine. In this section, I am going to explain how to deploy a virtual machine based on the 2016-Datacenter
image, within the WindowsServer
offer, from the MicrosoftWindowsServer
publisher.
To deploy the new virtual machine, which we are going to call myVM2
, you need to first capture some credentials to use as the local admin for the new virtual machine. To specify the local admin credentials for the new virtual machine, run the following command:
$cred = Get-Credential
To deploy a new virtual machine (called myVM2
), using the preceding information, run the New-AzureRmVm
command in a PowerShell session that’s been connected to your Azure tenant:
New-AzureRmVm `
-ResourceGroupName "VMLab" `
-Name "myVM2" `
-Location "EastUS" `
-VirtualNetworkName "myVnet" `
-SubnetName "mySubnet" `
-SecurityGroupName "myNSG" `
-PublicIpAddressName "myPublicIpAddress2" `
-ImageName "MicrosoftWindowsServer:WindowsServer:2016-Datacenter:latest" `
-Credential $cred `
-AsJob
The ImageName
switch specifies the value returned by the Get-AzureRmVMImageSku
command in the previous section. This is the switch that tells Azure what specific image to deploy the new virtual machine from.
The AsJob
switch creates the virtual machine as a background task and returns control of the PowerShell prompt to you, so you can continue working without needing to wait for the previous command to complete.
Since this command is deploying a virtual machine, it can take a while to complete. After a few minutes (usually 15 minutes or so), the new myVM2
virtual machine will be deployed:
Before continuing you can run the following Get-AzureRmVm
command and confirm that the myVM2
virtual machine is deployed and running:
Get-AzureRmVm -ResourceGroupName VMLab -Name MyVM2 -status
Assuming you did everything right, you will be able to see the following output, indicating that the new myVM2
virtual machine has been deployed and is running:
Using custom images
Sometimes, though, a default or marketplace image just isn’t sufficient for a virtual machine’s deployment. An example of this in the real world would be a case where several virtual machines with a particular application installed are needed. Another example would be a case where a gold image server image is maintained so that when a virtual machine is deployed from it, the server that gets deployed is already fully patched, negating the need to spend hours patching it up to date.
Enter Custom Images
Custom images are essentially the same as images available onthe marketplace. However, custom images are created by you. By using custom images, you can deploy preconfigured servers, saving yourself hours of post-deployment configuration.
In this section, we will create a custom image of an Azure virtual machine and use it to deploy a customized virtual machine.
You will learn how to do the following:
-
Sysprep and generalize a virtual machine
-
Create a custom image from an existing virtual machine
-
Create a new virtual machine from a custom image
-
List all the images in an Azure subscription
-
Delete an image
Before you begin
Throughout the rest of this exercise, I’m going to walk you through the steps required to take an existing virtual machine, create a custom image from it, and then use that image to deploy a new customized virtual machine based on the image. To follow along with this exercise, you need to have an existing Windows 2016 virtual machine, called myVM2
, in Azure to work with. It should be deployed to a resource group called VMLab
.
Preparing a virtual machine
The first step in deploying a virtual machine based on a custom image is to prepare the source virtual machine. Creating an image from a source virtual machine requires the source virtual machine to be generalized and deallocated. Once this has been completed, the source virtual machine needs to be marked as generalized in Azure. Only after these tasks have been completed can an image be made from the virtual machine.
Using sysprep
Sysprep is the tool that’s used to generalize the source virtual machine. It is a Windows utility that essentially removes all account information from a machine. What this tool does is remove security information, such as the SID/GUID, from a virtual machine and then it prepares the computer for a first-time boot— much like a new laptop would behave upon the initial boot.
Removing all security information from a virtual machine allows an image of it to be taken and used over and over without duplicate SIDs/GUIDs causing issues related to having multiple identical computers on the network.
To begin the process of preparing the myVM2
virtual machine to be used as an image, perform the following steps:
- Log in to the virtual machine using RDP and launch the Command Prompt as an administrator. Get the public IP for the virtual machine so you can RDP to it by running the following command:
Get-AzureRmPublicIpAddress `
-Name myPublicIPaddress2 `
-ResourceGroupName VMLab | Select IPAddress
- Once you’ve logged into
myVM2
, launch the command prompt as an admin and change to the%windir%\system32\sysprep
directory and runsysprep.exe
:
- From the
System Preparation Tool
dialog box, chooseEnter System Out-of-Box Experience(OOBE)
and make sure that the GeneralizeShutdown Options
, select ShutdownOK
:
- Clicking
Ok
launches the Sysprep process. When Sysprep completes, the virtual machine is automatically shut down.Do not restart the virtual machine!
Deallocating and generalizing
Before creating an image from the source virtual machine, the virtual machine must first be deallocated and marked as generalized in Azure:
- Confirm the
myVM2
virtual machine has been shut down by running theGet-AzureRmVm
command:
Get-AzureRmVm -Name MyVM2 -ResourceGroupName VMLab -status
- Stop and deallocate the virtual machine by running the following command:
Stop-AzureRmVm -ResourceGroupName VMLab -Name myVM2 -Force
- Run the
Get-AzureRmVm
command to be sure the virtual machine is stopped and deallocated:
Get-AzureRmVm -Name MyVM2 -ResourceGroupName VMLab -status
- Once the virtual machine has stopped and shows
deallocated
when you runGet-AzureRmVm
, set its status togeneralized
using theSet-AzureRmVm
command:
Set-AzureRmVM -ResourceGroupName VMLab -Name myVM2 -Generalized
- Running the preceding command deallocates the source virtual machine and marks it as generalized, preparing it for the imaging process. Confirm that the machine is generalized by running the
Get-AzureRmVm
command:
Get-AzureRmVm -Name MyVM2 -ResourceGroupName VMLab -status
You should see VM generalized as one of the statuses listed.
Creating an image
With the source virtual machine (myVM2
) generalized and deallocated, it can now be used to generate an image. Creating an image requires the use of two different PowerShell commands: New-AzureRmImageConfig
and New-AzureRmImage
.
To create an image from myVM2
, three things need to happen. First, the myVM2
virtual machine config needs to be loaded into a variable. Second, the image configuration needs to be created from myVM2
. And third, the actual image needs to be created.
Follow these instructions to complete the necessary steps.
Retrieving the source VM
Run the following command to retrieve the source myVM2
info and store it in a variable:
$vm = Get-AzureRmVM -Name myVM2 -ResourceGroupName VMLab
This command will not generate any feedback on the screen, since all it’s doing is loading info into a variable.
Creating an image configuration
Run the New-AzureRmImageConfig
command to create an image configuration that will be used to create the eventual image:
$image = New-AzureRmImageConfig `
-Location EastUS `
-SourceVirtualMachineId $vm.ID
Creating an image
The last step in image creation is the actual creation of the image from the image configuration. Run the New-AzureRmImage
command to create the actual image:
New-AzureRmImage `
-Image $image `
-ImageName myImage `
-ResourceGroupName VMLab
Upon completion of the preceding steps, you are left with a new image, called myImage
. The following screenshot shows the new image that was successfully created:
This image, based on the myVM2
virtual machine, can be used to deploy additional virtual machines that will be configured identically to myVM2
.
Creating a VM from an image
Once an image has been created, it can be used to provision additional virtual machines. Creating a new virtual machine in Azure from a custom image isn’t terribly different than creating a virtual machine using a typical Marketplace image.
When you deploy an Azure virtual machine from a Marketplace image, you must provide information about the image publisher, the offer, the SKU, and the version.
Using a basic set of parameters (switches) for the New-AzureRmVm
command allows you to just provide the name of the custom image (if it is in the same resource group as the virtual machine you are deploying).
The following New-AzureRmVm command will provision a new virtual machine in Azure, called myVM3
, using the image called myImage
. Run the command to create a new virtual machine, called MyVM3
:
New-AzureRmVm `
-ResourceGroupName "VMLab" `
-Name "myVM3" `
-ImageName "myImage" `
-Location "EastUS" `
-VirtualNetworkName "myVnet" `
-SubnetName "mySubnet" `
-SecurityGroupName "myNSG" `
-PublicIpAddressName "myPublicIP3"
Because you didn’t create local admin credentials before running the preceding command, you will be prompted to create local admin credentials. Once you supply them, the new myVM3
virtual machine will be provisioned. Running the New-AzureRmVm command should produce output similar to what you see here:
Once the preceding command completes, run the following command to retrieve the public IP for myVM3
and use it to RDP into the new virtual machine and confirm it functions as expected:
Get-AzureRmPublicIpAddress `
-Name myPublicIP3 `
-ResourceGroupName VMLab | Select IPAddress
Managing images
Deploying a new virtual machine from an image is all well and good. However, it helps to know how to perform some basic image-management tasks as well. You can use the following instructions to perform some common image-management tasks via PowerShell.
Listing images by name
The following command enables you to list all available images by name:
Find-AzureRmResource -ResourceType Microsoft.Compute/images
Deleting an Image
The following command deletes the myImage image from the VMLab resource group:
Remove-AzureRmImage -ImageName myImage -ResourceGroupName VMLab
Don’t worry, deleting the image won’t break the virtual machine that you deployed from it. The image just won’t be available to create any more VMs:
Congratulations!
You’ve now learned how to create a disk image from an existing virtual machine and then use that image to deploy a new virtual machine—all with PowerShell!
If you found this article interesting, you can explore Azure PowerShell Quick Start Guideto leverage PowerShell to perform many day-to-day tasks in Microsoft Azure. Taking you through the basic tasks of installing Azure PowerShell and connecting to Azure, Azure PowerShell Quick Start Guidewill help you learn to properly connect to an Azure tenant with PowerShell.