Uploading and creating a Custom Azure VM from .VHD

Creating a Custom VM from an Uploaded .VHD
Creating a VM from a predefined Image on the azure portal is easy, but when creating a custom VM from an uploaded .VHD is concerned, it can be tricky. This post will help in resolving the issues that are faced during the process.
I am going to create a VM in Hyper-V and will be taking the .VHD to azure Portal and would be creating a custom VM from the uploaded .VHD, so let’s get started.
Step1: Open Hyper-V

2. Click on New > Virtual Machine

3. Click, Next.

4. Specify the Name of the Virtual Machine, in this case Windows Server 2012. Now when selecting generation, please keep in mind that Microsoft Azure only supports generation 1 VM, so make sure to select GENERATION 1, the difference can be seen here.

5. Select Generation 1, select Next. Specify Memory, 1024, 2048 or if you have More RAM in your system, choose your own size.

6. In the Configure Networking section, specify if the VM will use the Virtual Switch or Not Connected, I suggest to select virtual network switch to install Updates on the Operating system to make it compatible for Azure.

7. Click Next, select “Create a virtual hard Disk”, specify location and select size. I would suggest making it 32 GB so that it won’t take too long to upload the .VHD file.

8. Click Next, Select install operating system from a bootable device, select Image and specify the location of the Image on your system.

9. See the Summary and click Finish.

10. You will see the Machine in the list of Virtual Machines.

11. Important !, Now since the machine is created, the Disk on which the VM is created is in .VHDX format that is not supported on Azure, we need to convert .VHDX to .VHD, to do that select the desired VM, click Edit Disk from the right menu.

12. Click Next,

13. Specify the Location where the .VHDX is located, Click Next and click Convert.

14. Select VHD and click Next,

15. Click Fixed Size and click Next.

16. Specify the Location, give it a Reasonable name and Click Finish.

17. It is going to take some time depending upon the size of the disk, once done, go back to the Hyper-V and Select New > VM.
Follow steps 2 to 7 and instead of using Create a Virtual Disk, select use an existing Virtual hard Disk that you have just Created.

18. specify the location of the converted .VHD file and click next, and Finish. Your VM with .VHD file is now created in the Hyper-V.
19. Right click the newly created from .VHD and click connect.

20. Go through the process of installing the OS. Once installation is complete, login into the Virtual machine and Run PowerShell with administrative privileges

Use these PowerShell Commands:

netsh winhttp reset proxy
san policy=onlineall

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation' -name "RealTimeIsUniversal" 1 -Type DWord
Set-Service -Name w32time -StartupType Auto
powercfg /setactive SCHEME_MIN

Check the windows Services
Set-Service -Name bfe -StartupType Auto
Set-Service -Name dhcp -StartupType Auto
Set-Service -Name dnscache -StartupType Auto
Set-Service -Name IKEEXT -StartupType Auto
Set-Service -Name iphlpsvc -StartupType Auto
Set-Service -Name netlogon -StartupType Manual
Set-Service -Name netman -StartupType Manual
Set-Service -Name nsi -StartupType Auto
Set-Service -Name termService -StartupType Manual
Set-Service -Name MpsSvc -StartupType Auto
Set-Service -Name RemoteRegistry -StartupType Auto

Update remote Desktop Registry Settings
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -Value 0 -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -name "fDenyTSConnections" -Value 0 -Type DWord

The RDP port is setup correctly (3389)
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "PortNumber" 3389 -Type Dword

The listener is listening in every network interface
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "LanAdapter" 0 -Type Dword

Configure the netework level authentication mode for the RDP connections
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "UserAuthentication" 1 -Type DWord

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "SecurityLayer" 1 -Type DWord

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "fAllowSecProtocolNegotiation" 1 -Type Dword

Set the Keep Alive Value
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -name "KeepAliveEnable" 1 -Type Dword
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -name "KeepAliveInterval" 1 -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "KeepAliveTimeout" 1 -Type DWord

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' -name "fDisableAutoReconnect" 0 -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "fInheritReconnectSame" 1 -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "fReconnectSame" 0 -Type Dword

Limit the number of concurrent connections
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp' -name "MaxInstanceCount" 4294967295 -Type Dword

If there are any self-signing Certificates tied to the RDP listener, remove them

Remove-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -name "SSLCertificateSHA1Hash"

Configure Windows Firewall Rules
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\services\SharedAccess\Parameters\FirewallPolicy\DomainProfile' -name "EnableFirewall" -Value 1 -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\services\SharedAccess\Parameters\FirewallPolicy\PublicProfile' -name "EnableFirewall" -Value 1 -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\services\SharedAccess\Parameters\FirewallPolicy\Standardprofile' -name "EnableFirewall" -Value 1 -Type Dword

Run the following command to allow WinRM through the three firewall profiles
Enable-PSRemoting -force
netsh advfirewall firewall set rule dir=in name="Windows Remote Management (HTTP-In)" new enable=yes
netsh advfirewall firewall set rule dir=in name="Windows Remote Management (HTTP-In)" new enable=yes

Enable the following firewall rules to allow RDP traffic

netsh advfirewall firewall set rule group="Remote Desktop" new enable=yes

Enable to file and printer sharing rule so that the vm can respond to a ping command inside a virtual network.

netsh advfirewall firewall set rule dir=in name="File and Printer Sharing (Echo Request - ICMPv4-In)" new enable=yes

Chkdsk /f
Make sure the report shows a clean and healthy disk.
Set the BCD settings in elevated command prompt

bcdedit /set {bootmgr} integrityservices enable

bcdedit /set {default} device partition=C:

bcdedit /set {default} integrityservices enable

bcdedit /set {default} recoveryenabled Off

bcdedit /set {default} osdevice partition=C:

bcdedit /set {default} bootstatuspolicy IgnoreAllFailures

Open Powershell again and set the following
winmgmt /verifyrepository

Make sure that any other service is not using port 3389
netstat -anob

Install the Azure VMs Agent. Then you can enable VM extensions. The VM extensions implement most of the critical functionality that you might want to use with your VMs such as resetting passwords, configuring RDP, and so on.

Create Dump log files with Powershell commands
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -name "CrashDumpEnable" -Value "2" -Type Dword
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -name "DumpFile" -Value "%SystemRoot%\MEMORY.DMP"
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -name "AutoReboot" -Value 0 -Type Dword
New-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps'
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpFolder" -Value "c:\CrashDumps"
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpCount" -Value 10 -Type Dword
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpType" -Value 2 -Type Dword
Set-Service -Name WerSvc -StartupType Manual

If you receive errors in creating dump file commands, type in the following commands
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -name "CrashDumpEnable" -Value "2" -Type Dword

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -name "DumpFile" -Value "%SystemRoot%\MEMORY.DMP"

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpFolder" -Value "c:\CrashDumps"

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpCount" -Value 10 -Type Dword

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -name "DumpType" -Value 2 -Type Dword

Set-Service -Name WerSvc -StartupType Manual

After the VM is created in Azure, we recommend that you put the pagefile on the ”Temporal drive” volume to improve performance. You can set up this as follows:

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management' -name "PagingFiles" -Value "D:\pagefile"

Once all the above steps are completed, goto settings in the VM and check online for updates and install any important updates, it is absolutely important to install all the updates before moving the VHD to Azure.

Now it is time to Sysprep the VM to make is compatible for Azure.

Run Command Prompt in elevated permissions. Navigate to System32 > Sysprep > Sysprep.exe

Make sure to select Enter System out-of-Box Experience (OOBE), click Generalize and Shutdown and Press OK.
Let the Wizard run and wait till the machine is shut down.

Now, its time to head back to Azure and do the rest there.
The first thing that needs to be done is to have PowerShell for Azure installed and configured on your machine. In order to install it, please navigate here.
Once installed, Run PowerShell in elevated permissions and type in the Following command

This command is going to ask for the Credentials for your Azure subscription.

This command will get all the subscription associated with your Credentials

Select-AzureRmSubscription -SubscriptionId ""
Select the desired subscription by replacing the SubscriptionID with your subscription ID
Create a new resource Group or Use Existing

New-AzureRmResourceGroup -Name myResourceGroup -Location "East US"

Create a new storage account in the Resource Group that you just created
New-AzureRmStorageAccount -ResourceGroupName myResourceGroup -Name mystorageaccount -Location "East US" -SkuName "Standard_LRS" -Kind "Storage"

Now you can either Upload the Blob from PowerShell or can Use Azure Storage Explorer. I am going to use Azure storage Explorer for the purpose. If you do not have storage explorer, you can download it from here.

Install Storage Explorer and click Add Account button to add your desired subscription. Once done, head back to Toggle Explorer button to see your Storage Account under your subscription.

At the Desired Container, click the Upload button on the top navigation.

Click the Upload and head to where you have your VHD Created Above, Select the File, Make sure Page Blob check box is selected, click Upload.

Depending upon the size of the .VHD file and the internet speed, the VHD will take some time to upload. Make sure it is 100% completed before proceeding to creating a VM from the VHD.
Once the VHD is uploaded, it is time to create the VM.
We will now create the Managed Image for the VHD, it is better to have the Managed image because you can later create as many VM's from this Managed Image through the Portal itself.
Head back to PowerShell and use the Command.

$vmName = "myVM"
$computerName = "myComputer"
$vmSize = "Standard_DS1_v2"
$location = "East US"
$imageName = "yourImageName"
$urlOfUploadedImageVhd = "Your VHD Location, this can be found in the Storage Explorer, by right clicking the VHD and select properties."

$imageConfig = New-AzureRmImageConfig -Location $location
$imageConfig = Set-AzureRmImageOsDisk -Image $imageConfig -OsType Windows -OsState Generalized -BlobUri $urlOfUploadedImageVhd
$image = New-AzureRmImage -ImageName $imageName -ResourceGroupName $rgName -Image $imageConfig

Once the Command is successful, Head back to the portal and to your resource Group. You are going to see Image File for the above commands.

Click on the desired Image and Click Create VM +

Click on the desired Image and Click Create VM +

The Next Steps are the same when you create a VM from the Azure Portal. Once Done, click create and wait for a while for the VM to be created.
In my case it took 10 + minutes for the VM to be created, once created, click the connect button and download the .RDP file. Give it the Username and Password and there you are, in your own custom VHD VM running on Azure. Happy Azuring !

Comments (0)

Skip to main content