Add existing vhd to Azure VM using PowerShell Azure Resource Manager cmdlets - powershell

NOTE: This is an Azure ARM question - not an Azure Service Management question.
I have 2 vhds in a storage account - machine-os.vhd and machine-data.vhd. I can use PowerShell ARM cmdlets to create a VM with the existing OS vhd, but cannot figure out how to attach the EXISTING data vhd. All the samples I have found create EMPTY data disks - but I want to attach the existing vhd as a data disk.
I've tried to use the createOption attach switch with Add-AzureVMDataDisk like so:
$vm = New-AzureVMConfig ...
$vm = Add-AzureVMDataDisk -VM $vm -VhdUri $existingDiskUri -Name "machine-data.vhd" -Caching ReadOnly -CreateOption attach -DiskSizeInGB 200
However, the operation fails with:
Blob https://x.blob.core.windows.net/vhds/machine-data.vhd already exists. Please provide a different blob URI to create a new blank data disk 'machine-data.vhd.'
I have to specify DiskSizeInGB for the Add-AzureVMDataDisk command to work (which seems strange). I've tried specifying SourceImageUri and a different name for the VhdUri, which, according to the documentation, should copy the vhd from the sourceImageUri to the vhdUri and attach it. Trying createOption fromImage fails because "you cannot specify size with source image uri". However, the size parameter for the cmdlet is mandatory, so I don't know how you could specify an sourceUri and not a size.
This SO question presents a similar issue (though I don't get the same error), but the link in the answer shows a template with EMPTY data disks, which doesn't help.
Interestingly I've tried to add the disk to the VM from the Azure Portal - there you have to specify a name and a URI, but the operation always fails with some strange json parsing error. I can't seem to get the uri for the data disk correct.

After playing around a bit more I found a hack:
Give a new URI for the existing disk and set this as the vhdUri
Use the URI of the existing disk as the sourceImageUri
Call Add-AzureVMDataDisk using the CreateOption fromImage
Set the size of the data disk to null (this is the hack)
When calling New-AzureVM, the existing disk is copied to the new Uri
After creating the VM, I delete the original vhd
Unfortunately you have to supply the DiskSizeInGB parameter to the Add-AzureVMDataDisk command since it's mandatory. However, I set it to null, otherwise the provisioning fails (the error message says that you can't specify both size and sourceImageUri).
Here's the final code:
$vm = New-AzureVMConfig ...
$vm = Add-AzureVMDataDisk -VM $vm `
-SourceImageUri $existingDataDiskUrl -VhdUri $newDataDiskUri `
-Name $newDataDiskName -CreateOption fromImage -Caching ReadOnly `
-DiskSizeInGB 200
# hack
$vm.StorageProfile.DataDisks[0].DiskSizeGB = $null
After that you can call:
New-AzureVM -ResourceGroupName $rgName -Location $location -VM $vm
Once the VM is created, I call Remove-AzureStorageBlob to delete the original disk.
Perhaps there's a cleaner way, but I can't find one. At least this way works in the end.

Related

Function to move/delete files within file share in Azure Storage Explorer?

I'm not proficient in Powershell yet, so please bear with me if I use the incorrect terminology.(And please correct me if I do.)
I have installed the Az and Azure.Storage modules.
I have also connected to my account using Connect-AZAccount (Is this the best way? Since you need to copy the URL and login via a browser)
Then I was just trying to view the files, to test the connection. Using Get-AzureStorageFile
This prompts me for a sharename - I used the name of the folder under File Shares in Azure Storage Explorer. But this failed, see failure below
cmdlet Get-AzureStorageFile at command pipeline position 1 Supply
values for the following parameters: (Type !? for Help.) ShareName:
bss get-azurestoragefile : Could not get the storage context. Please
pass in a storage context or set the current storage context.
Additional information to note, I do not have access to the Account Key, only the SAS Token.
Any help would be appreciated.
If you use Connect-AzAccount, you will use the Az module powershell Get-AzStorageFile instead of Get-AzureStorageFile. Before running the Get-AzStorageFile command, you need to pass the storage context with New-AzStorageContext to fix the error.
Sample:
$context = New-AzStorageContext -StorageAccountName "<StorageAccountName>" -StorageAccountKey "<StorageAccountKey>"
Get-AzStorageFile -ShareName "<ShareName>" -Path "<ContosoWorkingFolder>" -Context $context

VMs detailed properties using azure?

is there any way to get all VM's expanded properties and not just the ones Get-azurermvm brings, using powershell?
I was trying to use Select but I don't know where to get all the names. The ones on the Portal's Column won't work (bring back empty fields)
and if I use get-member, they don't bring anything because I think they are nested inside...
As I mentioned in my comment, this is not trivial because an Azure VM is not a self contained thing like a Hyper-V VM. There is no single source of truth because it is made of many components, and you would need to collect the information from those components individually. For example: Getting all of a VM's IP addresses.
To start getting IPs for a machine you get the VM info:
$VM = Get-AzureRmVm -ResourceGroup $RG -Name 'MyUberVM'
Now you can look at the network profile for the VM, which will list the Network Interface objects that are associated with VM, but those have all of 2 properties, Primary and Id. The Primary property is just what it sounds like, it specifies the primary network interface if you have more than one. The Id property will have the full ResourceId for the Network Interface object, something like:
/subscriptions/12345abc-0000-1111-2222-ssl430asd432/resourceGroups/MyVMRG/providers/Microsoft.Network/networkInterfaces/myubervm01715
Now we can use that to get the actual Network Interface object a couple ways, but the simplest is to just run Get-AzureRmResource against it, and pipe that to Get-AzureRmNetworkInterface.
$NIs = $VM.NetworkProfile.NetworkInterfaces.Id|%{Get-AzureRmResource -ResourceId $_}|Get-AzureRmNetworkInterface
That will get you a collection of Network Interface objects. Each of these will have several properties, but the one we care about is the IpConfigurations property. Each IpConfig of each Network Interface will have a PrivateIpAddress property, and a PublicIp property. The PrivateIp property is just a string, so we can use that, but the PublicIp is an object, so we will need to refer to it's IpAddress property. Now, this is going to potentially return more than one of each of those depending on how many network interfaces you have associated with a given VM, so I'll join them with ', ' just to be safe. To break that down, we can do:
$PrivateIps = $NIs.IpConfigurations.PrivateIpAddress -join ', '
$PublicIps = $NIs.IpConfigurations.PublicIp.IpAddress -join ', '
Thus ends the walk-through of getting the IPs for an Azure VM. That takes care of 2 of your suggested columns. Admittedly, two of the harder ones, but still just 2 of them none the less. Once you go through and get all of the data you need for each individual VM I'd make a custom object for it, and output those custom objects to your CSV file.
If my understanding is right, get-azurermvm could get all vms in your subscription, but you could not get detailed properties. You could use Get-AzurermVM get-azurermvm -ResourceGroupName $rg -Name $vm.Name to get detailed properties. You could try to use the following scripts.
##resource group name
$rg="<>"
$vms=get-azurermvm -ResourceGroupName $rg
ForEach ($vm in $vms) {
get-azurermvm -ResourceGroupName $rg -Name $vm.Name
}
Note: You could use get-azurermvm -ResourceGroupName $rg -Status to get VM's status information.

Attaching a locally uploaded VHD to a Classic Azure VM

I have a VHD I uploaded to Azure using the
Set-AzureStorageBlobContent
and attempted using the -
Add-AzureVhd
When I utilize the
Add-AzureDataDisk
in the console, the VHD appears to be attached to LUN 0 on the VM, when I utilize
Get-AzureVM I utilized the appropriate URI for the MediaLocation argument, but when I check the Classic Portal (Web Interface) or go into the VM itself, the VHD is still not attached.
If I do the process manually, the VHD attaches all fine and dandy. Under
VMs->Instances->Disks
I can see the VHD thats been uploaded there if I do the process manually, but utilizing cmdlets, I cannot seem to get the VHD to appear in "existing disks" via VM instances.
Now I have triple checked everything, my storage account is in the same region as my VM instance. My locally uploaded VHD is fixed and labeled correctly in blobs as "someVHD.vhd", when I attempt to use Add-AzureDataDisk, in the console it returns that the disk is attached, the weird behavior is that if I labelled the existing disk during the attach cmdlet arguments, the disk still does not attach utilizing cmdlets.
This is my exact script -
$createVHD = New-VHD -Path $($vhdInstallFullPath) -Fixed -SizeBytes 256MB -ComputerName $hostName
Copy files to VHD and prepare them for upload to azure utilizing either Set-AzureStorageBlobContent or Add-AzureVHD, in this case I utilized Set-AzureStorageBlobContent, because the VHD is really small.
$migrateVHD = Set-AzureStorageBlobContent -File $vhdInstallFullPath -Blob $VHDInstallName -Container $StorageContainerName -Context $($newAzureContext.Context) -BlobType Page -Confirm:$False
$addAzureDataDisk = Add-AzureDataDisk -VM $azureVMInfo -ImportFrom -MediaLocation $azureInstallBlobURI -DiskLabel "InstallPackage" -LUN $azureDataDiskLUN
Now I have a lot of variables and I'm doing a lot of other things to get the storage context, the Azure VM object, and copying files to the vhd before I uplaod, but that script block should give everyone my gist.
Could my issue possibly be between utilizing page blobs over block blobs for the VHD? From documentation I understood that a VHD with multiple files would want to be a page blob.
Maybe you could try to use the following cmdlet.
Get-AzureVM "stlcs01" -Name "shuitest1" | Add-AzureDataDisk -ImportFrom -MediaLocation "https://t5portalvhdsx2463gvmvrz7.blob.core.windows.net/vhds/shui-shui-2017-02-02.vhd" -DiskLabel "InstallPackage" -LUN 1
I find a good article about your problem, maybe you could check this article:Add, Import Data Disk to Azure Virtual Machine using Powershell.
I test in my lab.
Add-AzureVhd -Destination “https://t5portalvhdsx2463gvmvrz7.blob.core.windows.net/vhds/shui.vhd” -LocalFilePath “D:\shui.vhd” -NumberOfUploaderThreads 32
Get-AzureVM -name shuitest -ServiceName shuitest | Add-AzureDataDisk -ImportFrom -MediaLocation “https://t5portalvhdsx2463gvmvrz7.blob.core.windows.net/vhds/shui.vhd” -DiskLabel “test” -LUN 1
Get-AzureVM -ServiceName shuitest -Name shuitest|Get-AzureDataDisk

How do I reconfigure the Azure diagnostics extension when recreating an Azure VM

I need to make changes to a Azure Resource Manager Virtual Machine that are not allowed on an existing machine, such as changing the availability group. So I have to delete and recreate the machine, attaching the existing disks, network adapters, etc. to the new VM. I have a PowerShell script to do this, but I'm running into a problem with Virtual Machine extensions.
Here's my code:
$NewVMConfig = New-AzureRmVMConfig -VMName $VM.Name -VMSize $VM.HardwareProfile.VmSize
$NewVMConfig = Set-AzureRmVMOSDisk -VM $NewVMConfig -Name $VM.StorageProfile.OSDisk.Name -VhdUri $VM.StorageProfile.OSDisk.VHD.Uri -CreateOption attach -Windows
foreach ($disk in $vm.StorageProfile.DataDisks) {
$NewVMConfig = Add-AzureRmVMDataDisk -VM $NewVMConfig -Name $disk.Name -VhdUri $disk.Vhd.Uri -Caching $disk.Caching -DiskSizeInGB $disk.DiskSizeGB -CreateOption attach -Lun $disk.Lun
}
$NewVMConfig.AvailabilitySetReference = $VM.AvailabilitySetReference
$NewVMConfig.DiagnosticsProfile = $VM.DiagnosticsProfile
$NewVMConfig.Extensions = $VM.Extensions
$NewVMConfig.NetworkProfile = $VM.NetworkProfile
$location = $VM.Location
$resourceGroupName = $VM.ResourceGroupName
# Delete machine.
Remove-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name
# Recreate machine
New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location -VM $NewVMConfig
Notice the line:
$NewVMConfig.Extensions = $VM.Extensions
The script runs without any error, but the new VM doesn't have the same extensions as the original. The diagnostics extension is gone and it now has the BGInfo extension which wasn't on the original machine.
I can use the Remove-AzureRmVMExtension command to remove the BGInfo extension, but I have been unsuccessful at recreating the diagnostics extensions. I've tried both Set-AzureRmVMExtension and Set-AzureRmVMDiagnosticsExtension to no avail.
Those VM extension commands do not support ARM yet. Hence, I suggest you to use ARM template instead. There is a quick-start template specifically for Windows VM with diagnostics extension on GitHub. You can download it and modify it to meet your needs, like specifying a VHD for your VM. And, use New-AzureRmResourceGroupDeployment to deploy your vm.
For your case, combining the above template with 201-specialized-vm-in-existing-vnet template would meet your needs.
Note: the 201-vm-diagnostics-extension-windows template deploys a Windows VM with diagnostics extension, while the 201-specialized-vm-in-existing-vnet template deploys a VM with existing VNet and VHD
For more information about this, see Create a Windows Virtual machine with monitoring and diagnostics using Azure Resource Manager Template.
For more information about authoring ARM template, see Authoring Azure Resource Manager templates.
For more information about deploying ARM template, see Deploy a Resource Group with Azure Resource Manager template.
Jack Zeng's answer with the virtual machine template showed me what was missing in my attempts to reconfigure the Azure diagnostics extension.
The key is that when you get a VM and look at the Extensions property (or the ExtensionsText property) it doesn't include the protected settings of the extension. (That's one way in which they are protected.) Thus you don't have all the information you need to recreate the extension. You have to rebuild the protected settings, which would vary from extension to extension, so you need to know what the specific extension requires. The virtual machine template to which Jack provide a link shows what information is needed for the protected settings of the Azure diagnostics extension, namely the storage account name, key, and endpoint.
Running the following code after recreating the virtual machine successfully reconfigured the diagnostics. In this code $VM is the original virtual machine object we got from calling Get-AzureRmVM before recreating the machine.
$diagnosticsExtension = $VM.Extensions | Where { $_.Name -eq 'Microsoft.Insights.VMDiagnosticsSettings' }
# The $VM.Extensions.Settings property does not correctly return the values of the different settings.
# Instead, use the $VM.ExtensionsText property to get the old settings.
$oldSettings = $VM.ExtensionsText | ConvertFrom-Json | Where { $_.Name -eq 'Microsoft.Insights.VMDiagnosticsSettings' } | foreach {$_.'properties.settings'}
# Need settings in a hash table.
$settings = #{
xmlCfg = $oldSettings.xmlCfg;
StorageAccount = $oldSettings.StorageAccount
}
$storageAccounts = Get-AzureRmStorageAccount
$storageAccount = $storageAccounts | Where { $_.StorageAccountName -eq $settings.StorageAccount }
$storageAccountKeys = $storageAccount | Get-AzureRmStorageAccountKey
$protectedSettings = #{
storageAccountName = $settings.StorageAccount;
storageAccountKey = $storageAccountKeys.Key1;
storageAccountEndPoint = "https://core.windows.net/"
}
Write-Host "Reconfiguring Azure diagnostics extension on $Name..."
$result = Set-AzureRmVMExtension -ResourceGroupName $newVM.ResourceGroupName -VMName $newVM.Name -Name $diagnosticsExtension.name -Publisher $diagnosticsExtension.Publisher -ExtensionType $diagnosticsExtension.VirtualMachineExtensionType -TypeHandlerVersion $diagnosticsExtension.TypeHandlerVersion -Settings $settings -ProtectedSettings $protectedSettings -Location $diagnosticsExtension.Location
Note that I am running version 1.2.1 of the Azure PowerShell extensions. In this release, Set-AzureRmVMDiagnosticsExtension appears to be broken, so I did not use it.

Remove-AzureDisk throws error, not sure why

I have an Azure VM and I'm trying to delete it using Powershell. I also want to remove the disk that that VM OS was on (there are no data disks).
I assume I'm going to need the following two cmdlets:
Remove-AzureVM
Remove-AzureDisk
Here's my code:
$VMs = Get-AzureVM $svcName
foreach ($VM in $VMs)
{
$OSDisk = ($VM | Get-AzureOSDisk)
if ($VM.InstanceStatus -eq "ReadyRole") {
Stop-AzureVM -Name $VM.Name -ServiceName $svcName
}
remove-azurevm -ServiceName $svcName -Name $VM.Name
Remove-AzureDisk -DiskName $OSDisk.DiskName
}
When I execute this the call to Remove-AzureVM returns successfully but the call to Remove-AzureDisk returns an error:
Remove-AzureDisk : BadRequest: A disk with name
XXX is currently in use
by virtual machine YYY running within hosted service
ZZZ, deployment XYZ.
Strange thing is, I can issue the same call to Remove-AzureDisk just a few moments later and it returns successfully.
Its as if the call to Remove-AzureVM is returning too quickly. i.e. Its reporting success before the VM has been fully removed, or before the link to the disk has been removed at any rate.
Can anyone explain why this might be and also how I might work around this problem?
thanks in advance
Jamie
What's happening here is that the Disk that is stored in BLOB storage is locked when in use by a VM. You are removing the VM, but it takes a few moments for the Lease on the BLOB to release. That's why you can remove it a few moments later.
There are a few folks who have written PowerShell to break the lease, or you could use PowerShell to use the SDK (or make direct REST API calls) to check lease status.
I ended up writing a script that creates a VM, clones it, then deletes the clones. As part of that I needed to wait until the lease was released hence if you're experiencing this same problem you might want to check my blog post at http://sqlblog.com/blogs/jamie_thomson/archive/2013/11/04/clone-an-azure-vm-using-powershell.aspx as it'll have some code that might help you.
Regards
Jamie
I puzzled at this for quite a while. Ultimately, I found a different command to do what I thought I was doing with this command. I would recommend the remove-azuredatadisk command to delete a disk, as it automatically breaks the lease.
Get-AzureVM -ServiceName <servicename> -name <vmname> |Remove-AzureDataDisk -lun <lun#> -deletevhd | Update-AzureVM
It will spin for a couple of minutes, but it will give you a success/failure output at the end.
This command just does it, and doesn't give you any feedback about which drive was removed. I would recommend tossing in a get-azuredatadisk first just to be sure of what you deleted.
Get-AzureVM -ServiceName <servicename> -name <vmname> | Get-AzureDataDisk
This is related to Windows Azure: Delete disk attached to non-existent VM. Cross-posting my answer here:
I was unable to use the (2016) web portal to delete orphaned disks in my (classic) storage account. Here is a detailed walk-through for deleteing these orphaned disks with PowerShell.
PowerShell
Download and install PowerShell if you haven't already. (Install and configure Azure PowerShell.) Initial steps from this doclink:
Check that the Azure PowerShell module is available after installing:
Get-Module –ListAvailable
If the Azure PowerShell module is not listed, you may need to import it:
Import-Module Azure
Login to Azure Resource Manager:
Login-AzureRmAccount
AzurePublishSettingsFile
Retreive your PublishSettingsFile.
Get-AzurePublishSettingsFile
Get-AzurePublishSettingsFile launches manage.windowsazure.com and prompts you to download an XML file that you can be saved anywhere.
Reference: Get-AzurePublishSettingsFile Documentation
Import-AzurePublishSettingsFile and specify the path to the file just saved.
Import-AzurePublishSettingsFile -PublishSettingsFile '<your file path>'
Show and Remove Disks
Show current disks. (Reference: Azure Storage Cmdlets)
Get-AzureDisk
Quickly remove all disks. (Credit to Mike's answer)
get-azuredisk | Remove-AzureDisk
Or remove disks by name. (Credit to Remove-AzureDisk Documentation)
Remove-AzureDisk -DiskName disk-name-000000000000000000 -DeleteVHD