How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks

9 min read

Introduction

Microsoft introduced back in June 2017 a new type of storage account called “Managed Disks“. Managed Disks are an exciting feature from Azure, which is designed to help with the availability, manageability, scalability, and performance of virtual machine disks storage within Azure.

Starting with Azure Stack build 1808, Microsoft announced support for managed disks on Azure Stack as well. This update simplifies disk management for Azure Stack VMs by managing the disk associated with the VM. You only have to specify the type (Premium or Standard) and the size of the disk you need and Azure Stack creates and manages the disk for you. This work will bring more options and simplicity to Azure Stack users when working with VMs. Beginning with the 1811 update, Azure Stack managed disks are enabled by default when creating VMs using the Azure Stack portal. Furthermore, Microsoft strongly recommends converting your standard disks in Azure Stack to managed disks.

Azure Stack managed disks are NOT featured parity with Azure, there are some key differences that you should be aware of. Please make sure to continuous reading Microsoft documentation here to see the differences.

The question is, what if you have an existing Azure Stack VMs with unmanaged standard disks, can I convert them to managed disks? The short answer is, YES!

In this post, I will show you how to automate the conversion of Azure Stack virtual machines from unmanaged to managed disks and remove the extra layer of administrative overhead.

If you still have Azure VMs with unmanaged disks laying around, please check my previous article on how to convert them to Azure managed disks.

Convert Azure Stack VMs To Managed Disks

If you have some virtual machines deployed on Azure Stack before you used managed disks, or you decided to simplify and go from an unmanaged disk configuration to a managed disk configuration. Either way, it’s a long process and it’s completely different than converting Azure VM managed disks.

The Azure PowerShell cmdlets ConvertTo-AzureRmVMManagedDisk and ConvertTo-AzVMManagedDisk can’t be used to convert an unmanaged disk to a managed disk in Azure Stack. Azure Stack doesn’t currently support those cmdlets at the time of this writing. Additionally, the Azure Stack portal cannot be used to convert an unmanaged disk to a managed disk. The only way to convert an Azure Stack VM with unmanaged to managed disk is to delete the VM, detach the disks and then recreate the virtual machine with managed disk as described by Microsoft documentation here.

To convert Azure Stack VM to a managed disk, you need first to remove the VM configuration before you create the new VM with a managed disk. So you’ve to take that into consideration in terms of things like downtime, availability of your applications. But if this is a non-critical VM then it’s not a big deal, you can go ahead and convert it anytime.

In this example, I’ve got a VM named vm-azs-sql0, vm-azs-sql0 uses unmanaged disks. As you can see in the screenshot below, it’s got an operating system OS disk and 2 Data disks.

How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks 1

If I click on the OS disk or any data disks, you can see it’s actually using a storage account. So this is an unmanaged disk.

How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks 2

The VM is also a member of an Availability Set. It has also a public IP address, NIC interface, and Network Security Group configured.

How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks 3

The process of converting an Azure Stack VM from unmanaged to managed disk is as follows:

  1. Specify the VM that you want to convert and in which Azure Stack subscription is hosted.
  2. Specify the Resource Group Name.
  3. Specify the location where the VHDs are located that will be used to create the managed disks. The VHD file(s) can be deleted as soon as the managed disks are created (Step 10).
  4. Get the network configuration (vNET, vNIC, NSG, Public IP address).
  5. Get the storage account for the Boot Diagnostics settings.
  6. If the VM is a member of an availability set, you need to convert the Availability Set from classic to managed.
  7. Delete the VM only without its disks.
  8. Create the OS managed disk configuration (Linux / Windows).
  9. Create the Data managed disk configuration.
  10. Delete the old VHD file(s).
  11. Create the network configuration back.
  12. Add the VM to the availability set.
  13. Attach the Boot Diagnostics storage account.
  14. Finally, recreate the virtual machine with it’s managed disks.

As you can see, there are a lot of steps that you want to go through and it’s not a simple task, especially if you have a lot of VMs to convert.

To facilitate this process, I have created a PowerShell tool that will automate the entire process for you.

You can run the script as follows:

.EXAMPLE

.\Convert-AzSManagedDisk.ps1 -rgFQDN [region.FQDN] -AADTenantName [domain.com] -AzSCred [[email protected]] -VMName [VMName] -Storageacc [StorageAccountName] -Verbose

This example will convert a specified Azure Stack VM from unmanaged to a managed disk, this could be running on Azure Stack Integrated System or on Azure Stack Development Kit, you need to specify the region and the external FQDN of the Azure Stack, as well as the username and the storage account where the VHDs are located. If the VM has multiple data disks attached to it, the tool will convert them all to managed disks.

Here is an example of the output once you run this tool:

How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks 4

Once the VM is recreated, you will see that all disks are created as managed disks now. The whole network configuration will be preserved.

How To Convert Azure Stack VM From Unmanaged Disks To Managed Disks 5

PowerShell Code

The complete script is detailed below to automate the entire process:

<#
.SYNOPSIS
Convert Azure Stack VMs to managed disks.

.DESCRIPTION
Convert Azure Stack VMs from Standard (unmanaged) disks to managed disks.

.NOTES
File Name : Convert-AzSManagedDisk.ps1
Author    : Charbel Nemnom
Version   : 1.0 
Date      : 08-August-2019
Update    : 13-August-2019
Requires  : PowerShell Version 5.1 or above
Module    : Azure Stack Version 1.7.1 and above
Version   : Azure Stack version 1808 and above
Support   : Azure Stack Development Kit and Azure Stack Integrated System
OS        : Convert Windows or Linux VMs

.LINK
To provide feedback or for further assistance please visit: https://charbelnemnom.com

.EXAMPLE
.\Convert-AzsManagedDisk.ps1 -rgFqdn  -AADTenantName  -AzsCred <[email protected]> -VMName  -storageacc  -Verbose
This example will convert a specified Azure Stack VM from unmanaged to managed disk, this could be running on Azure Stack Integrated System or Azure Stack Development Kit, you need to specify the region and the external FQDN of the Azure Stack, as well as the username and the storage account where the VHDs are located.
#> 

[CmdletBinding()]
Param (
 [Parameter(Position=0, Mandatory=$true, HelpMessage = 'Provide the region and external FQDN of the Azure Stack')]
 [Alias('fqdn')]
 [String]$rgFqdn,
 
 [Parameter(Position=1, Mandatory=$true, HelpMessage = 'Provide the Azure AD (AAD) Tenant Name')]
 [Alias('AAD')]
 [String]$AADTenantName,  

 [Parameter(Position=2, Mandatory=$True, HelpMessage ='Provide Azure Stack Credentials')]
 [Alias('Cred')]
 [PSCredential]$AzsCred,

 [Parameter(Position=3, Mandatory=$True, HelpMessage ='Provide the Azure Stack VM Name that you want to convert')]
 [Alias('VM')]
 [String]$VMName,
 
 [Parameter(Position=4, Mandatory=$true, HelpMessage ='Provide the Azure Stack Storage Account where the VHDs exist')]
 [Alias('StorageAccount')]
 [String]$storageacc
 )

# Azure Stack 1904 or later (only)
 Function Install-AzureRM {
    Set-PSRepository -Name PSGallery -Installation Trusted -Verbose:$false
    Install-Module -Name AzureRM.BootStrapper -Confirm:$false -Verbose:$false    
}

# Azure Stack 1904 or later (only)
Function Install-AzureStack {
    Set-PSRepository -Name PSGallery -Installation Trusted -Verbose:$false
    Use-AzureRmProfile -Profile 2019-03-01-hybrid -Force -Confirm:$false -Verbose:$false   
    Install-Module -Name AzureStack -RequiredVersion 1.7.2 -Confirm:$false -Verbose:$false
 }

# Install Azure RM AvailabilitySet
Function Install-AzureRmAvailabilitySet {
Try {
    Import-Module -Name AzureRm.AvailabilitySetManagement -ErrorAction Stop -Verbose:$false | Out-Null
    Write-Verbose "Importing Azure RM AvailabilitySet PowerShell Module..."
    }
Catch {
    Write-Warning "Azure RM AvailabilitySet PowerShell Module is not installed..."
    Write-Verbose "Installing Azure RM AvailabilitySet Module..."
    Set-PSRepository -Name PSGallery -Installation Trusted -Verbose:$false   
    Install-Module -Name AzureRm.AvailabilitySetManagement -Confirm:$false -Verbose:$false
    }
}

#! Check Azure Stack Connection
Try {
    Write-Verbose "Connecting to Azure Stack..."
    Add-AzureRmEnvironment –Name ‘AzureStackUser’ -ArmEndpoint "https://management.$rgfqdn"  | Out-Null
    # Set your AAD tenant name
    $AuthEndpoint = (Get-AzureRmEnvironment -Name "AzureStackUser").ActiveDirectoryAuthority.TrimEnd('/')
    $TenantId = (invoke-restmethod "$($AuthEndpoint)/$($AADTenantName)/.well-known/openid-configuration").issuer.TrimEnd('/').Split('/')[-1]
    # Signing into Azure Stack
    Add-AzureRmAccount -EnvironmentName "AzureStackUser" -Credential $AzsCred -TenantId $TenantId -ErrorAction Stop | Out-Null    
}
Catch {
    Write-Warning "Cannot connect to Azure Stack environment. Please check your credentials. Exiting!"
    Break
}

#! Check AzureRM BootStrapper PowerShell Module
Try {
    Import-Module -Name AzureRM.BootStrapper -ErrorAction Stop -Verbose:$false | Out-Null
    Write-Verbose "Importing Azure RM BootStrapper PowerShell Module..."
}
Catch {
    Write-Verbose "Installing the Azure RM BootStrapper Module..."
    Install-AzureRM
}

#! Check Azure Stack PowerShell Module
Try {
    Import-Module -Name AzureStack -RequiredVersion 1.7.2 -ErrorAction Stop -Verbose:$false | Out-Null
    Write-Verbose "Importing Azure Stack PowerShell Module..."
}
Catch {
    Write-Warning "Azure Stack PowerShell Module requires update..."
    Write-Verbose "Installing Azure Stack PowerShell Module version 1.7.2"
    Install-AzureStack
}

# Get all Azure Stack Tenant Subscriptions and look for the VM that you want to convert
# The source and target VM will be created
Write-Verbose "Get all Azure Stack Tenant Subscriptions..." 
$azsSubs = Get-AzureRmSubscription

Write-Verbose "Locate Azure Stack VM ($VMName)..." 
$azsVM = $azsSubs | ForEach-Object {Select-AzureRMSubscription $_ | Out-Null; Get-AzureRMVM | Where-Object {$_.Name -eq $VMName} }

If (!$azsVM ) {
Write-Warning "Azure Stack virtual machine ($VMName) cannot be found. Please check your virtual machine name. Exiting!"
Break
}

# Set the context to the subscription ID in which the managed disk will be created.
Write-Verbose "Set the context to the Azure Stack subscription ID: $($azsVM.Id.Split('/')[2])"
Select-AzureRmSubscription -SubscriptionId $azsVM.Id.Split('/')[2] | Out-Null

# Get the virtual NIC interface name and details 
$NicName = $azsVM.NetworkProfile.NetworkInterfaces.Id.Split('/')[-1]
$vNic = Get-AzureRmNetworkInterface -Name $NicName -ResourceGroupName $azsVM.ResourceGroupName

# Get the public ip address name where the virtual machine will be hosted.
If ($VNic.IpConfigurations.publicIPAddress.Id -ne $null) {
 Write-Verbose "Get the public ip address of the virtual machine..."   
 $PIpName = $VNic.IpConfigurations.publicIPAddress.Id.Split('/')[-1]
}

# Get the virtual network name where the virtual machine will be hosted.
Write-Verbose "Get the virtual network name where the virtual machine will be hosted..."
$vnetName = Get-AzureRmVirtualNetwork -ResourceGroupName $azsVM.ResourceGroupName `
| % {if($_.Subnets.IpConfigurations.Id.StartsWith($azsVM.NetworkProfile.NetworkInterfaces.Id)){return $_.Name}}

# Get the Boot Diagnostics storage account
If ($azsVM.DiagnosticsProfile.BootDiagnostics.Enabled -eq $true) {
$azsVMstoragediag = $azsVM.DiagnosticsProfile.BootDiagnostics.StorageUri.Split("//")[2]
$azsVMstoragediag = $azsVMstoragediag.Split('.')[0] 
}

# Check if the VM that you want to convert to managed disks is in an availability set
If ($azsVM.AvailabilitySetReference.Id -ne $null) {
Install-AzureRmAvailabilitySet
Write-Verbose "Check if the VM that you want to convert is a member of an AvailabilitySet..."
$avSetName = $azsVM.AvailabilitySetReference.Id.Split('/')[-1]
Write-Verbose "Convert the availability set ($avSetName) to a managed availability set..."
$avSet = Get-AzureRmAvailabilitySet -ResourceGroupName $azsVM.ResourceGroupName -Name $avSetName
Update-AzureRmAvailabilitySet -AvailabilitySet $avSet -Sku Aligned | Out-Null
} 

#! Get storage account and Blob VHDs Uri URL.
Write-Verbose "Get the storage account and Blob VHDs Uri..."
$azsStorage = Get-AzureRmStorageAccount -ResourceGroupName $azsVM.ResourceGroupName -Name $storageacc
Set-AzureRmCurrentStorageAccount -Name $storageacc -ResourceGroupName $azsVM.ResourceGroupName | Out-Null
$storageContainerName = (Get-AzureStorageContainer).Name 
$azsdisks = @($azsvm.StorageProfile.OsDisk)
if ($azsvm.StorageProfile.DataDisks.Vhd.Uri) {
$azsdisks += $azsvm.StorageProfile.DataDisks
}

# Delete old VM, but keep the OS and data disks.
Write-Verbose "Remove Azure Stack VM $($azsVM.Name) configuration, the VM is going offline..."
Remove-AzureRmVm -Name $azsVM.Name -ResourceGroupName $azsVM.ResourceGroupName -Force -Confirm:$false | Out-Null

foreach ($azsdisk in $azsdisks) { 

# The size of the new disk in GB. It should be greater than the existing VHD file size.
$NewDiskSize = ($azsdisk.DiskSizeGB)+1

# Create the managed disk configuration.
$DiskConfig = New-AzureRmDiskConfig -AccountType $azsStorage.Sku.Name -Location $azsVM.Location -DiskSizeGB $NewDiskSize `
-SourceUri $azsdisk.Vhd.Uri -CreateOption Import 

if ($azsdisk.Name -eq "osdisk") { 
    # Create virtual machine configuration
    Write-Verbose "Create virtual machine configuration..."
    If ($avSetName) {
    Write-Verbose "Add the VMName $($azsVM.Name) to a managed availability set ($avSetName)"
    $VirtualMachine = New-AzureRmVMConfig -VMName $azsVM.Name -VMSize $azsVM.HardwareProfile.VmSize -AvailabilitySetId $avSet.Id
    }
    Else {
    $VirtualMachine = New-AzureRmVMConfig -VMName $azsVM.Name -VMSize $azsVM.HardwareProfile.VmSize
    }
    # Create OS managed disk.
    Write-Verbose "Create the OS managed disk: $($azsVM.Name)-$($azsdisk.Name)"
    $OsDisk = New-AzureRmDisk -DiskName "$($azsVM.Name)-$($azsdisk.Name)" -Disk $DiskConfig -ResourceGroupName $azsVM.ResourceGroupName
    
    # Use the managed disk resource ID to attach it to the virtual machine.
    # The OS type will be set according to the exisitng VM (Windows/Linux).
    If ($azsdisk.ostype -eq "Windows") {
    $VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -ManagedDiskId $OsDisk.Id -CreateOption Attach -Windows -Caching $azsdisk.Caching 
    }
    Else {
    $VirtualMachine = Set-AzureRmVMOSDisk -VM $VirtualMachine -ManagedDiskId $OsDisk.Id -CreateOption Attach -Linux -Caching $azsdisk.Caching 
    }
    # Delete the OS disk VHD file
    Remove-AzureStorageBlob -Container $storageContainerName -Blob "$($azsdisk.Vhd.Uri.Split('/')[-1])" -Force -Confirm:$false
}
Else {
    # Create Data managed disks.
    Write-Verbose "Create the Data managed disk: $($azsdisk.Name)"
    $DataDisk = New-AzureRmDisk -DiskName $azsdisk.Name -Disk $DiskConfig -ResourceGroupName $azsVM.ResourceGroupName
    
    # Create the Data managed disk configuration.
    $VirtualMachine = Add-AzureRmVMDataDisk -VM $VirtualMachine -ManagedDiskId $DataDisk.Id -CreateOption Attach -Lun $azsdisk.Lun `
    -Caching $azsdisk.Caching
    
    # Delete the Data disk VHD file
    Remove-AzureStorageBlob -Container $storageContainerName -Blob "$($azsdisk.Vhd.Uri.Split('/')[-1])" -Force -Confirm:$false 
    }
}

# Create a public IP for the VM.
If ($PIpName) {
$PublicIp = Get-AzureRmPublicIpAddress -Name $PIpName -ResourceGroupName $azsVM.ResourceGroupName
}

# Get the virtual network where the virtual machine will be hosted.
$VNet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $azsVM.ResourceGroupName

# Create NIC in the first subnet of the virtual network.
$Nic = Get-AzureRmNetworkInterface -Name $NicName -ResourceGroupName $azsVM.ResourceGroupName
$VirtualMachine = Add-AzureRmVMNetworkInterface -VM $VirtualMachine -Id $Nic.Id

# Enable Boot Diagnostics with the appropriate storage account.
if ($azsVMstoragediag) {
$VirtualMachine = Set-AzureRmVMBootDiagnostics -VM $VirtualMachine -Enable -StorageAccountName $azsVMstoragediag -ResourceGroupName $azsVM.ResourceGroupName
}

# Create the new virtual machine with managed disks.
Write-Verbose "Create the new virtual machine ($($azsVM.Name)) with managed disks..."
New-AzureRmVM -VM $VirtualMachine -ResourceGroupName $azsVM.ResourceGroupName -Location $azsVM.Location

Summary

Azure Stack VMs deployed with managed disk simplifies disk management by managing the disk associated with the VM. You only have to specify the type (Premium or Standard) and the size of the disk you need and Azure Stack creates and manages the disk for you. This work will bring more options and simplicity to Azure Stack users when working with VMs. And with this tool, it becomes even faster to convert any VM (test or production, Linux or Windows) from unmanaged to managed disk.

Roadmap

I am planning to improve this tool in the future. This is still version 1.0. If you have any feedback or changes that everyone should receive, please feel free to leave a comment below.

That’s it there you have it. Enjoy Azure Stacking!

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

About Charbel Nemnom 577 Articles
Charbel Nemnom is a Cloud Architect, Swiss Certified ICT Security Expert, Microsoft Most Valuable Professional (MVP), and Microsoft Certified Trainer (MCT), totally fan of the latest's IT platform solutions, accomplished hands-on technical professional with over 17 years of broad IT Infrastructure experience serving on and guiding technical teams to optimize the performance of mission-critical enterprise systems. Excellent communicator is adept at identifying business needs and bridging the gap between functional groups and technology to foster targeted and innovative IT project development. Well respected by peers through demonstrating passion for technology and performance improvement. Extensive practical knowledge of complex systems builds, network design, business continuity, and cloud security.

Be the first to comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.