- Create a certificate-signed RDP shortcut via Group Policy - Fri, Aug 9 2019
- Monitor web server uptime with a PowerShell script - Tue, Aug 6 2019
- How to build a PowerShell inventory script for Windows Servers - Fri, Aug 2 2019
Microsoft Azure, among many other things, gives users the ability to easily spin up virtual machines at will in their datacenters. There's no more worrying about purchasing and maintaining your own hardware anymore. A new VM is just an API call away.
To build these VMs, Microsoft provides you with hundreds of images in their Virtual Machine marketplace. You can find VMs with a vanilla install of Windows Server, CoreOS, Linux, and even Oracle.
However, what if you've already spent time tweaking your own custom images that you've been deploying with on-prem servers for a long time? You might not want to have to go through all of that with a new image and would prefer to use your existing image. The good news is that you can!
If your image is in a VHD format, by using a little PowerShell know-how and enough bandwidth to support a big data transfer, you can upload your VHD to Azure and use it as a template, just like you have done with your on-prem VMs. Here's how.
Note: In this article, I will be focusing on v2 VMs, or Azure Resource Manager (ARM) VMs. I will not be discussing v1 or ASM VMs. If you're still using ASM, I encourage you to look into ARM.
First, as I mentioned, you will need to ensure your image is in a VHD format. If you're lucky, it might already be, and you're good to go. However, if it's in another format, it can be converted. If it's in a VHDX format, a cmdlet called Convert-VHD exists that's readily available on your Hyper-V hosts. By using this cmdlet, simply pass in your VHDX with the path to your VHD, and out will come a VHD ready to be uploaded to Azure. If you've got VMware's VMDK, you can use the Microsoft Virtual Machine Converter to do the conversion, as well.
Once you've got the VHD to upload, you'll then need to ensure you have the Azure PowerShell module installed and that you have provided your Azure credentials to authenticate. I'm also going to assume you've already got a resource group setup, storage account created, and a container in that storage account to which to upload the VHD. Now you're ready to upload your VHD to your Azure storage account.
When uploading files to Azure you typically have two options; to use the Set-AzureStorageBlobContent cmdlet for general files or Add-AzureRmVhd for VHDs. When I first attempted this, I tried to use Set-AzureStorageBlobContent, which resulted in a couple of corrupted VHDs. Even though this method will get a VHD onto your Azure storage account and appears to work, I don't recommend it. Always use Add-AzureRmVhd instead. This cmdlet will ensure your VHD is uploaded as a page block type (required for VHDs), as well.
To get started, you'll first need to obtain the storage container endpoint that resides inside of the storage account. One way to do this is by passing the storage account to the Get-AzureStorageContainer cmdlet.
Let's say I have a storage account called 'MyStorageAccount' with a storage container called 'MyContainer' in a resource group called 'MyRG'. I can retrieve this storage account using the Get-AzureRmStorageAccount cmdlet. Then, I can immediately pipe that output directly to Get-AzureStorageContainer, specifying the name of the container into which I'd like to upload the VHD.
$storageContainer = Get-AzureRmStorageAccount –ResourceGroupName 'MyRG' –Name 'MyStorageAccount' | Get-AzureStorageContainer -Container $ContainerName
Now I can retrieve the blob endpoint for the storage container, which is required for the VHD destination.
$containerBlob = $storageContainer.Context.BlobEndPoint
We now have all the pieces we need to make this happen. At this point, I'll simply need to pass in the resource group name, the destination VHD path, and the path to the VHD that's stored locally.
Add-AzureRmVhd –ResourceGroupName 'MyRG' –Destination "$containerBlob/MyContainer/MyVHD.vhd" –LocalFilePath 'C:\MyVHD.vhd'
When you do this, it will begin to generate a hash of the VHD. This is to ensure that, once the blob has been created, it's exactly the same as it was when it left your computer. The hashing and upload takes a while. If it's taking too long, you can look into upping the thread count by specifying the -NumberOfUploaderThreads parameter.