- Proxmox Backup Server: Install and configure - Fri, May 19 2023
- Using Docker with NAS and NFS - Mon, May 15 2023
- Create a Proxmox cluster - Fri, May 5 2023
Azure baseline images can be of two types: specialized images and generalized images. A specialized image is used to create only one VM, whereas a generalized image can be used to create multiple clone VMs. In this post, we will focus on creating a generalized Azure image by removing machine-specific information from it, which is suitable for cloning.
For demonstration purposes, I will use a Hyper-V VM running Windows Server 2022 with a preconfigured IIS server, SFTP server, and a business web app. You can have any application running on your VM that you want to include in your custom Azure image. Be aware that the system preparation tool (sysprep), which we will use later to generalize the OS, does not support all server roles. Check the supported roles here.
You will need the following prerequisites to follow along with this guide:
- Active Azure subscription
- Azure Az PowerShell module installed
- Windows machine with Hyper-V installed
- A generation 1 VM running with the required OS and set of applications (in our case, Server 2022, IIS, SFTP server, and business web app). Azure offers generation 2 VMs, but to avoid any issues, I recommend using a generation 1 VM.
Prepare your virtual machine
First, make sure you have configured your VM the way you like. For this demo, I've made sure that the IIS role is installed, an SFTP server is configured, and a business app is working on the VM as expected.
In addition, you also need to adjust a few Windows settings. These settings are not required, but are recommended to ensure you can connect the new VM that you will provision later in your Azure account. Log in to your VM, and follow these steps:
The Azure platform mounts an ISO file to a DVD drive when creating a VM from a generalized image. So, we will set the SAN policy to OnlineAll to ensure that the system brings all newly discovered disks online and makes them available for read/write. To do so, launch diskpart in your VM, and type the following command:
san policy=OnlineAll (iView and change the SAN policy using diskpartg)
Run the following PowerShell commands to enable RDP and make sure it is set to use the default port number and network-level authentication:
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -Value 0 -Type DWord -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" -Name fDenyTSConnections -Value 0 -Type DWord -Force Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp" -Name PortNumber -Value 3389 -Type DWord -Force Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" -Name UserAuthentication -Value 1 -Type DWord -Force
You can also enable PowerShell remoting using the following PowerShell command:
Enable Windows firewall and necessary rules:
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled True Set-NetFirewallRule -Name FPS-ICMP4-ERQ-In, RemoteDesktop-UserMode-In-TCP, WINRM-HTTP-In-TCP, WINRM-HTTP-In-TCP-PUBLIC, IIS-WebServerRole-QUIC-In-UDP, IIS-WebServerRole-HTTPS-In-TCP, IIS-WebServerRole-HTTP-In-TCP, OpenSSH-Server-In-TCP -Enabled True
Create new rules to allow bidirectional communication to the virtual public IP address of the Azure platform:
New-NetFirewallRule -DisplayName AzurePlatform -Direction Inbound -RemoteAddress 184.108.40.206 -Profile Any -Action Allow -EdgeTraversalPolicy Allow New-NetFirewallRule -DisplayName AzurePlatform -Direction Outbound -RemoteAddress 220.127.116.11 -Profile Any -Action Allow
Make sure all Windows updates are installed, and the VM is not pending a restart. You can restart it one more time to be sure.
Finally, you need to run sysprep on your VM. To do so, run the following PS commands:
Remove-Item -Path "C:\Windows\Panther" -Recurse C:\Windows\System32\Sysprep\sysprep.exe /generalize /shutdown /oobe
Sysprep now automatically turns off the VM. You shouldn't turn it back on until you've uploaded the VHD to Azure.
Prepare your virtual hard disk
Now you need to prepare your VM's virtual hard disk so that it can be uploaded to Azure. Before you can upload, the disk needs to meet the following prerequisites:
- The disk format must be VHD.
- The disk type must be Fixed.
- The virtual size must be a multiple of one (1) MB.
- The minimum virtual size must be at least 20 MB.
The Azure Az PowerShell module offers an Add-AzVHD cmdlet, which can handle all the conversion, resizing, optimization, and upload operations, but it requires Hyper-V to be installed. If Hyper-V isn't available, you need to manually convert and optimize the virtual disk with the following PowerShell commands:
Get-VHD "D:\VM\SRV301.vhdx" Convert-VHD -Path "D:\VM\SRV301.vhdx" -DestinationPath "D:\VM\SRV301.vhd" -VHDType Fixed The Get-VHD command gives you information about the current virtual hard disk. If you notice that the disk is not properly aligned, use the Resize-VHD command, as shown below: Resize-VHD -Path D:\VM\SRV301.vhd -SizeBytes 30GB
You need to take care while specifying the value of the -SizeBytes parameter so that the resultant size is a multiple of 1 MB, as required by Azure. Assuming that the current size of my disk is 27.5 GB, I extended it to 30 GB.
Since we already have Hyper-V installed, we will just use the Add-AzVHD cmdlet to automatically prepare the virtual hard disk and upload it from our on-premises machine to Azure.
Prepare to upload VHD
If Azure Az PowerShell is not installed on your machine, you can install it with the following command:
Install-Module -Name Az -Repository PSGallery -Force
Now I'll use the Connect-AzAccount cmdlet to connect my Hyper-V host to Azure and type the credentials in the popup window to log in to my Azure account.
Connecting the Azure account using the Connect-AzAccount cmdlet
Next, run the following command to create a new resource group:
New-AzResourceGroup -Name awesomeResourceGroup01 -Location eastus
Skip this step if you want to use one of your existing resource groups.
Upload VHD and create a generalized disk
Finally, use the Add-AzVHD cmdlet, as shown below, to upload the virtual hard disk to Azure:
Add-AzVhd -LocalFilePath "D:\VM\SRV301.vhdx" -ResourceGroupName awesomeResourceGroup01 -Location eastus -DiskName myServerDisk -NumberOfUploaderThreads 32
This command uses Hyper-V functionality to convert an existing VHDX to a new VHD disk in the same directory, optimize it by detecting empty blocks, calculate the MD5 hash of a new disk, and then upload it directly to a managed disk named myServerDisk in Azure. The command could take a while to finish, so you just have to be patient.
When the disk is uploaded, you can use the Get-AzDisk cmdlet to view the uploaded VM's information:
Get-AzDisk -ResourceGroupName "awesomeResourceGroup01" -DiskName "myServerDisk"
Create a custom Azure image from disk
Now that you have created a managed disk in Azure, we will use it to create a generalized OS image. To do so, run the following PowerShell commands:
$locationName = "eastus" $imageName = "imgServer2022" $resourceGroup = "awesomeResourceGroup01" $managedDisk = Get-AzDisk -ResourceGroupName "awesomeResourceGroup01" -DiskName "myServerDisk" $imageCfg = New-AzImageConfig -Location $locationName $imageCfg = Set-AzImageOsDisk -Image $imageCfg -OsState Generalized -OsType Windows -ManagedDiskId $managedDisk.Id New-AzImage -ImageName $imageName -ResourceGroupName $resourceGroup -Image $imageCfg
The above commands will create a generalized OS image with the name imgServer2022 using the virtual disk you uploaded to Azure. You can view the managed image with the following command:
Get-AzImage -ResourceGroupName "awesomeResourceGroup01" -ImageName "imgServer2022"
Launch a new VM using a custom Azure image
We can now create a new VM using the managed OS image we created in the previous step. When creating a new VM, click the See all images link under the Image field, click My Images in the left section, and then select the imgServer2022 image. See the screenshots below for reference:
Set all other fields as required, and click the Review + Create button. Now, wait while the new VM is provisioned for you.
Connect to the new VM
Once the VM is successfully provisioned and started, click the VM name and select the Networking option. Make sure the necessary inbound port rules are configured. In my case, I created a few rules to allow the RDP, SFTP server (SSH), and HTTP(S) ports.
When you connected to the VM via RDP, we can verify that IIS, the SFTP server, and the web app are already running on the new VM.
Subscribe to 4sysops newsletter!
You just created a custom Azure image. The image is generalized, so you can use it as a baseline image to provision any number of VMs, saving you a lot of time and effort.
Want to write for 4sysops? We are looking for new authors.
how would i take a production on-prem server vm and move it to azure
You can use the same procedure as mentioned in this post. If you’re going to be creating only a single VM in Azure from imported disk, you could skip the Sysprep step.