Microsoft has introduced the ability to create managed disks in Azure a while ago. This feature takes away the manual management overhead for you to keep track of your storage account limits. Managed disks are not stored in “regular” storage accounts, but Microsoft will take care of the VHD placement and will keep track of any IOPS limitions.
For example, a Standard Size VM allows 500 IOPS per disk. The maximum IOPS for a Standard storage account is 20.000 IOPS. This means that you can host a maximum of 40 disks (OS or Data) in a Standard storage account. When you use unmanaged disks, you’ll need to keep track of this limitation yourself. When using managed disks, Microsoft will make sure the 500 IOPS per disk is available, regardless of the storage account.
The conversion of an unmanaged disk to managed is very easy; Microsoft created the ConvertTo-AzureRmVMManagedDisk CmdLet for this. But if you want to convert back from managed to unmanaged, no CmdLet or function in the Azure portal is available for the conversion (for example Azure Site Recovery; very nice feature of Azure, but it doesn’t support managed disks). Converting back to unmanaged is a bit harder, but still possible.
Converting from managed to unmanaged
Converting a managed disk to an unmanaged disk basically means you need to copy the managed VHD file to one of your storage accounts and create a VM using that copied VM. The step-by-step process to convert back to unmanaged is as follows:
- Get the Managed Disk object using Get-AzureRmDisk
- Grant Access to the Managed Disks using Grant-AzureRmDiskAccess
- Copy the VHD to your storage account using Start-AzureStorageBlobCopy
- Detach any Network Interfaces from the original VM
- Recreate the VM using the copied VHDs
- Attach the Network Interfaces
Copying the VHD to a storage account
First of all, you should retrieve the disk name using the following commands:
$vm = Get-AzureRmVM -ResourceGroupName RESOURCEGROUPNAME -Name VMNAME $vm.StorageProfile.OsDisk | Where-Object {$_.ManagedDisk -ne $null} | Select-Object Name $vm.StorageProfile.DataDisks | Where-Object {$_.ManagedDisk -ne $null} | Select-Object Name
This retrieves all the managed disks (both OS and Data) from the defined VM. You should not the names of the disks you need to convert. Next, you have to create a storage context which can later be used to copy the VHDs (you can retrieve the storage account key using the portal, or using Get-AzureRmStorageAccountKey):
$context = New-AzureStorageContext -StorageAccountName STORAGEACCOUNTNAME -StorageAccountKey STORAGEACCOUNTKEY
Once you created the context, you can grant access and start the blob copy. To keep track of the asynchronous copy action, you can pass the output of the Start-AzureStorageBlobCopy cmdlet to a variable and later on check the status using Get-AzureStorageBlobCopyState.
$sas = Grant-AzureRmDiskAccess -ResourceGroupName RESOURCEGROUPNAME -DiskName DISKNAME -Access Read -DurationInSecond (60*60*24) $blobcopyresult = Start-AzureStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestinationContainer "vhds" -DestinationBlob "YOURDISKNAME.vhd" -DestinationContext $context
During the copy phase, you can retrieve the status using the following command:
$blobcopyresult | Get-AzureStorageBlobCopyState
Recreating the VM
Once the copy job is done, I’d rename the old VM to eg. VMNAME_old; this way you can always switch back to the old VM if anything goes wrong. To connect the new VM to the same virtual network, you can detach the network interfaces from the old VM, so we can attach them again to the new VM. You should take note of those NICs before detaching them, so we can attach them later easily.
Recreating a VM from the copied VHD can be done using the following commands:
$vmconfig = New-AzureRmVMConfig -VMName VMNAME -VMSize "VMSIZE" $vm = Add-AzureRmVMNetworkInterface -VM $vmConfig -Id (Get-AzureRmNetworkInterface -Name NICNAME -ResourceGroupName RESOURCEGROUPNAME).Id $vm = Set-AzureRmVMBootDiagnostics -VM $vm -Enable -ResourceGroupName RESOURCEGROUPNAME-StorageAccountName BOOTDIAGNOSTICSSTORAGEACCOUNTNAME $vm = Set-AzureRmVMOSDisk -VM $vm -VhdUri (Get-AzureStorageBlob -Context $context -Blob "YOURDISKNAME.vhd" -Container "vhds").ICloudBlob.uri.AbsoluteUri -CreateOption Attach -Name "YOURDISKNAME" New-AzureRmVM -ResourceGroupName RESOURCEGROUPNAME -Location westeurope -VM $vm
Additional configuration
Note that you is possibly that you need to do some additional configuration. You’ll need to remember the following from your original VM:
- VM Extensions
- Availability set
- Auto-shutdown
- Configuration (Managed Service Identity and Azure hybrid benefit)
If you need to deploy the VM in an availability set, be sure to include this during re-creation:
$vmconfig = New-AzureRmVMConfig -VMName VMNAME -VMSize "VMSIZE" -AvailabilitySetId AVAILABILITYSETID
I hope this article was useful for you. If you have any questions, please don’t hesitate to leave a comment or contact me over email. |
Thanks for this!
One question, I used Azure integrated powershell and the session expires after 20min. How can I get the copy status again?
Hi Bruno,
You should be able to get the status after restarting the cloud shell by using these commands:
Set-AzureRmCurrentStorageAccount -ResourceGroupName RESOURCEGROUPNAME -Name STORAGEACCOUNTNAME
Get-AzureStorageBlobCopyState -Container “vhds” -Blob “NAMEOFYOURDISK.vhd”
Thanks!
oh, by the way, when you recreate the VM you need to specify the osType and caching.
vm = Set-AzureRmVMOSDisk -VM $vm -VhdUri (Get-AzureStorageBlob -Context $context -Blob “YOURDISKNAME.vhd” -Container “vhds”).ICloudBlob.uri.AbsoluteUri -CreateOption Attach -Name “YOURDISKNAME” -Windows -Caching ReadWrite
Set-AzureRmVMOSDisk -Windows, otherwise you will get “osDisk.osType” is missing (null). Also missed space in “RESOURCEGROUPNAME-StorageAccountName”. Thank you.
Grant Access command returning null
$sas = Grant-AzureRmDiskAccess -ResourceGroupName RESOURCEGROUPNAME -DiskName DISKNAME -Access Read -DurationInSecond (60*60*24)
hence $sas.AccessSAS is null.
Is there another way to pass the URI or am I missing anything ?
thanks for the post
is that working for data disks as well?
Hi, yes this works for data disks as well. The first command gets the disk names for both OS and data disks.
i have same error. How i have to fix it?
For this,
$blobcopyresult = Start-AzureStorageBlobCopy -AbsoluteUrl $sas.AccessSAS -DestinationContainer “vhds” -DestinationBlob “TestVM_OsDisk_1_f010ae5b471c461fa86ef2748a7858e1.vhd” -DestinationContext $context
I’m getting result
Start-AzureStorageBlobCopy : A parameter cannot be found that matches parameter name ‘AbsoluteUrl’.
At line:1 char:46
+ $blobcopyresult = Start-AzureStorageBlobCopy -AbsoluteUrl $sas.Access …
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-AzureStorageBlobCopy], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.WindowsAzure.Commands.Storage.Blob.Cmdlet.StartAzureStorageBlobCopy
Please help
Hi,
check what’s inside the $sas variable; if the Grant-AzureRmDiskAccess command failed or returned a value that was not expected, the Start-AzureStorageBlobCopy command will fail.
Hi,
This command return the following message error:
$vm = Set-AzureRmVMBootDiagnostics -VM $vm -Enable -ResourceGroupName MYRG -StorageAccountName mystorage04
Set-AzVMBootDiagnostic : Cannot validate argument on parameter ‘VM’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:1 char:40
+ $vm = Set-AzureRmVMBootDiagnostics -VM $vm -Enable -ResourceGroupName …
+ ~~~
+ CategoryInfo : InvalidData: (:) [Set-AzVMBootDiagnostic], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Azure.Commands.Compute.SetAzureVMBootDiagnosticsCommand
Please, i appreciate your help…
Hi Floris,
I got this error, How can I fix it please?
PS Azure:\> New-AzureRmVM -ResourceGroupName Aquatech-AZR-Prod -Location CanadaCentral -VM $vm
New-AzureRmVM : Changing property ‘osDisk.vhd.uri’ is not allowed.
ErrorCode: PropertyChangeNotAllowed
ErrorMessage: Changing property ‘osDisk.vhd.uri’ is not allowed.
ErrorTarget: osDisk.vhd.uri
StatusCode: 409
ReasonPhrase: Conflict
OperationID : 3447fc49-e225-4ff7-b51b-e1e4595ba086
At line:1 char:1
+ New-AzureRmVM -ResourceGroupName Aquatech-AZR-Prod -Location CanadaCe …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzVM], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.NewAzureVMCommand