Attaching Existing OS VHD to New Virtual Machine in Microsoft Azure Using Azure PowerShell
Post date: Nov 01, 2019 6:53:43 AM
The previous post "Attaching Existing OS VHD to New Virtual Machine in Microsoft Azure" showed how to attach an existing OS VHD page blob to a newly created virtual machine using Azure Xplat-CLI. This post shows how to do the same using Azure PowerShell.
Work on this post began in June 2017, then stopped for more than two years. Since then, PowerShell has gone cross platform with PowerShell Core, on Windows, GNU/Linux and macOS; the AzureRM module used for this post will be deprecated, replaced by Azure PowerShell Az module that works with PowerShell Core. However, the concepts demonstrated in this post will be useful for using the Azure PowerShell Az module.
Details of Existing OS VHD
The VHD has SUSE Linux Enterprise 12 SP1 installed from Azure image.
Storage Account: cglssd
Resource group: default-storage-southeastasia
Location: Southeast Asia
Performance: Premium
Replication: Locally-redundant storage (LRS)
Container: vhds
VHD page blob name: triton22016525164553.vhd
URL: https://cglssd.blob.core.windows.net/vhds/triton22016525164553.vhd
Type: Page blob
Size: 30 GiB
Network security group ID: /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/Default-Storage-SoutheastAsia/providers/Microsoft.Network/networkSecurityGroups/triton2
This OS VHD is the old unmanaged disk. The new Azure Managed Disks provide new features and should be used for new VHDs. While it is possible to convert unmanaged disk to Managed Disk, I have not done so.
Note that the so called location is actually the Azure region. You need the appropriate "location" for the commands below.
Azure PowerShell vs Azure Xplat-CLI
While Azure Xplat-CLI is cross platform CLI and works on Windows, Mac and GNU/Linux, Azure PowerShell is limited to Windows clients.
The power of Azure Xplat-CLI is that it can be part of BASH shell scripts and BASH is now available on Windows, Mac and GNU/Linux. Therefore Azure Xplat-CLI should be more portable and is easier to use for people who are used to Unix programs and shell.
For people who are very conversant with PowerShell, it is an easy decision to adopt Azure PowerShell. It is then a matter of learning the Azure specific commands to manage Azure resources.
Since PowerShell is very different from Unix shells, there is a learning curve for people who are not familar with it. PowerShell works with objects, that makes it very powerful, but also much more difficult to understand.
Installing Azure PowerShell
Azure PowerShell is not installed as part of Windows by default and has to be installed.
All the work done for this post were done on Windows Server 2016 Enterprise Edition, that was fully updated when work on this post began, which was in June 2017.
Installing Azure PowerShell from the PowerShell Gallery requires elevated privileges. Run the following command from an elevated PowerShell session (as administrator):
Install-Module AzureRM
Running Azure PowerShell
One should run Azure PowerShell as a non-administrator user. Too many people like to login to Windows with user accounts that have administrator privileges to do non-administrator tasks . People with Unix backgrounds like me treat administrator accounts with the utmost respect and use it only when necessary. I would say Microsoft is partly to blame; during Windows installation and also out-of-box experience of a new computer with Windows already pre-installed, user accounts with administrator privilege are created and many people simply continue to use the same accounts for daily work.
At the beginning of each session, to use Azure PowerShell, import the Azure module:
Import-Module AzureRM
Login to Azure
We are ready to go, well almost.
Azure PowerShell requires a web browser to login to Azure. The user credentials are typed into the browser. I have not verified if IE Is mandatory
Run the following command:
Login-AzureRmAccount
Login to Azure using Internet Explorer for the First Time in Windows Server 2016
On a desktop Windows like Windows 10, using a browser to login to Azure is not an issue. To login to Azure in Windows Server 2016 for the very first time is an adventure by itself if one is using Internet Explorer with Enhanced Security Configuration enabled by default. The most expedient way is to turn off Enhanced Security Configuration of Internet Explorer.
For the sake of curiosity, I decided to try using Internet Explorer with enhanced security enabled and document the results. It appears that in this mode, most web sites on the internet, including domains names belonging to Microsoft, are blocked by default. One has to manually add these to the allowed list.
I did not expect that there are so many web sites involved in Azure PowerShell login to Azure. Each time Internet Explorer showed a web site that got blocked, I added it to the allowed list, then I got notified that another web site got blocked.
See the screen shots, captured in 2017, below. Right Click on the screen shots below to open the images in new tab in actual size.
Finally, after going through so much trouble, we have completed the login process:
Normal Login to Azure
This is the normal Azure login screen after typing command "Login-AzureRmAccount":
Upon successful login:
Complete Sequence
We will show the complete sequence of using Azure PowerShell to attach an existing OS VHD page blob to a newly created virtual machine. The command parameters are verbose and most are self-explanatory. We will also examine the objects created for learning. Examination of objects is not necessary, but can be used for verification checking. Right Click on the screen shots below to open the images in new tab in actual size.
PowerShell and Module Version
Version of PowerShell and AzureRM:
Import Azure Module and Login to Azure
Import the Azure module:
______________________________________________________________________________________
Import-Module AzureRM
______________________________________________________________________________________
Login to Azure:
______________________________________________________________________________________
Login-AzureRmAccount
______________________________________________________________________________________
Type in the appropriate user ID. Next screen:
Select the appropriate account to use.
Type in the password.
We are logined to Azure:
Virtual Network
Create a virtual network subnet configuration:
______________________________________________________________________________________
$subnet1 = New-AzureRmVirtualNetworkSubnetConfig -Name "vnet1-subnet1" -AddressPrefix "10.0.1.0/24"
______________________________________________________________________________________
Note that we are only creating $subnet1 object at the client side, there are no configuration changes done in Azure.
Examination of $subnet1 object:
Create a virtual network, with the subnet configuration in $subnet1 object:
______________________________________________________________________________________
$vnet1 = New-AzureRmVirtualNetwork -Name "vnet1" -ResourceGroupName "default-storage-southeastasia" -Location "southeastasia" -AddressPrefix "10.0.0.0/16" -Subnet $subnet1
______________________________________________________________________________________
The virtual network has been created in Azure.
Examination of $vnet1 object:
Network Interface With Public IP Address
Create a public IP address that is static:
______________________________________________________________________________________
$pubIP1 = New-AzureRmPublicIpAddress -Name "triton-reborn-pubip1" -DomainNameLabel "triton-reborn" -ResourceGroupName "default-storage-southeastasia" -Location "southeastasia" -AllocationMethod Static -IpAddressVersion IPv4
______________________________________________________________________________________
The public IP address has been created in Azure.
Examination of $pubIP1 object:
Create a network interface, attached to the created subnet using the property in $vnet1 object, with a specified private IP address, with the created public IP address attached; bind an existing network security group named "triton2" that allows inbound connection only from my client IP address:
______________________________________________________________________________________
$nic1 = New-AzureRmNetworkInterface -Name "triton-reborn-nic1" -ResourceGroupName "default-storage-southeastasia" -Location "southeastasia" -SubnetId $vnet1.Subnets[0].Id -PrivateIpAddress "10.0.1.5" -PublicIpAddressId $pubIP1.Id -NetworkSecurityGroupId "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/Default-Storage-SoutheastAsia/providers/Microsoft.Network/networkSecurityGroups/triton2"
______________________________________________________________________________________
The network interface has been created in Azure.
Examination of $nic1 object:
Create Virtual Machine
Create a configurable virtual machine object; we configure with virtual machine name "triton-reborn", and the specified virtual machine size:
______________________________________________________________________________________
$VirtualMachine = New-AzureRmVMConfig -VMName "triton-reborn" -VMSize "Standard_DS2_v2"
______________________________________________________________________________________
Only $VirtualMachine object has been created at client side. No changes have been done in Azure.
Examination of $VirtualMachine object:
Add the network interface we just created to the virtual machine object:
______________________________________________________________________________________
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $nic1.Id
______________________________________________________________________________________
Only $VirtualMachine object has been updated at client side. No changes have been done in Azure.
Examination of $VirtualMachine object:
Set the operating system disk properties on the virtual machine object. We attach the existing OS VHD:
______________________________________________________________________________________
$VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -Name "triton22016525164553.vhd" -VhdUri "https://cglssd.blob.core.windows.net/vhds/triton22016525164553.vhd" -CreateOption Attach -Linux
______________________________________________________________________________________
Only $VirtualMachine object has been updated at client side. No changes have been done in Azure.
Examination of $VirtualMachine object:
Create a virtual machine with the configuration in the virtual machine object $VirtualMachine:
______________________________________________________________________________________
New-AzureRmVM -ResourceGroupName "default-storage-southeastasia" -Location "southeastasia" -VM $VirtualMachine -Verbose
______________________________________________________________________________________
The virtual machine creation has succeeded. The virtual machine has been reborn.
Get all the virtual machines in subscription:
Get the properties of the created virtual machine:
Get the instance view of the created virtual machine:
The original virtual machine was created from Azure SUSE Linux Enterprise 12 SP1 image. You can see from above that the Azure agent successfully started in the virtual machine.
I SSHed into the virtual machine, ran yast and successfully updated SUSE Linux Enterprise 12 SP1. The OS VHD had been sitting dormant for more than two years. Azure has changed tremendously since then, even the Azure portal interface has changed, however, the virtual machine booted up and is running flawlessly. Everything still works as before.
See the screen shot of the OS log:
The hypervisor can be seen to be Microsoft HyperV.
We again examine $VirtualMachine object:
"DiagonsticsProfle" property of $VirtualMachine object has been updated after virtual machine creation.
Azure Portal
This is the Azure portal showing overview of "triton-reborn":
Azure Portal Serial Console
Azure portal now has interactive serial console. This will make it much easier to do troubleshooting and rescue. There is a scroll bar on the right side to scroll up to the previous lines and it is possible to do copy and paste of the text.
Conclusions
The more than two years journey of demonstrating how to use Azure PowerShell to attach an existing OS VHD to a newly created virtual machine in Microsoft Azure has finally been completed.
There are many functions that are not available in the Azure portal. One has to use command line tools. Command line tools are also sometimes more convenient to use than the portal, especially for repetitive tasks and repeatable deployments.
Azure PowerShell is one of the available command line tools. PowerShell is a standalone shell environment; PowerShell Core, while available on multiple OS including GNU/Linux, will not work with the other shells in GNU/Linux.
PowerShell works with objects. One has to be clear whether an Azure PowerShell command only creates or updates an object at client side, with no changes done at Azure, or changes will be done at Azure as well. When using Azure PowerShell, one also has to be very careful so as to know when information is read only from client side object, or the actual information is retrieved from Azure.