Copy Azure OSDisks V DataDisks and powershell set Lun at 0 - azure

I have a couple of questions
I'm copying some OS disks and some data disks, and I'm using the same process for both, which is create snapshot and then creating disks from the snapshots. I've read a bit online where there's two processes for what appears to be the same task. Is there any difference between the OS Disk and Data Disk when you take a snapshot and create a disk from the snapshot?
Also I'm trying to attach the aforementioned data disks and the LUN number always starts at 1, would anyone know how I can get it to start at 0. The code I have is
$dataDisks = Get-AzDisk | ? {$_.name -like "*$ddisk*"}
$lun = 0
foreach ($disk in $dataDisks){
$lun += 1
$vm = Add-AzVMDataDisk -CreateOption Attach -VM $vm -Lun $lun -ManagedDiskId $disk.Id
Update-AzVM -VM $vm -ResourceGroupName $VMRG -Verbose
}
Thanks in advance and apologies if this seems like a lot of questions in one post :)

OS disk and data disk snapshots should behave the same as the snapshot is taken of the VM in order to be able to roll-back the changes done on the disks until they're consolidated on the VM.
Regarding your other issue:
foreach ($disk in $dataDisks){
$vm = Add-AzVMDataDisk -CreateOption Attach -VM $vm -Lun $lun -ManagedDiskId $disk.Id
Update-AzVM -VM $vm -ResourceGroupName $VMRG -Verbose
$i++ # You were modifying the variable before it it had finished.
}

I have been doing a lot of subscription migrations and need to be able to move and attach data disks, pretty similar.
I always just start mine with this:
$lun = -1
## If multiple Data Disks it will prompt for the LUN, start at 0
foreach ($ddisk in $datadisks) {
$luns = ++$lun
$getddisk = Get-AzDisk -ResourceGroupName $destinationrg -DiskName $ddisk
Write-output $ddisk.id
$newvm = Add-AzVMDataDisk -vm $newvm -Name $ddisk -CreateOption Attach -
ManagedDiskId $getddisk.id -Caching Readonly -storageaccounttype
Premium_LRS -Lun $luns
}

Related

VM Created from Image with Azure Powershell does not set ComputerName

I have an Azure Image, which when I use Azure Powershell to create a VM from, despite me setting the ComputerName in the script, the VM is created without setting the ComputerName to the provided value.
Script:
$ImageName = 'MyImage'
$RsgName = 'MyRsg'
$VmName = 'MyNewVM'
$DiagnosticStorageName = 'diagnosticsstore5048'
$cred = Get-Credential -Credential 'TheAdmin'
$Image = Get-AzureRmImage -ImageName $ImageName -ResourceGroupName $RsgName
# Get NIC
$nic = Get-AzureRmNetworkInterface -ResourceGroupName $RsgName
# Configure the new VM
$Vm = New-AzureRmVMConfig -VMName $VmName -VMSize 'Standard_A2_v2'
$Vm = Set-AzureRmVMSourceImage -VM $Vm -Id $Image.Id
$Vm = Set-AzureRmVMOSDisk -VM $Vm -Name $VmName'-disk' -StorageAccountType 'StandardLRS' -DiskSizeInGB '128' -CreateOption FromImage -Caching ReadWrite
$Vm = Add-AzureRmVMNetworkInterface -VM $Vm -Id $nic.Id
$Vm = Set-AzureRmVMBootDiagnostics -VM $Vm -Enable -ResourceGroupName $RsgName -StorageAccountName $DiagnosticStorageName
$Vm = Set-AzureRmVMOperatingSystem -VM $Vm -Windows -ComputerName 'dor' -Credential $Cred -ProvisionVMAgent
New-AzureRmVM -VM $Vm -ResourceGroupName $RsgName -Location 'West Europe' -DisableBginfoExtension
Last time I run the script to create the VM, it left the new VM with a computer name of 'WIN-I80O6J22ENS'
The Image was created as per the process here: https://learn.microsoft.com/en-gb/azure/virtual-machines/windows/capture-image-resource?toc=%2Fazure%2Fvirtual-machines%2Fwindows%2Fclassic%2Ftoc.json
UPDATE
Alot of people think that I am not Generalizing the image correctly, so I wanted to add here how I am doing it.
Inside the VM I run:
Start-Process -FilePath $env:windir\System32\Sysprep\Sysprep.exe -ArgumentList "/generalize /oobe /shutdown /unattend:$env:windir\System32\Sysprep\unattend.xml"
Unattend.xml only has one setting in it which is to step the TimeZone.
Once this is completed and the VM OS has shut down, I run the following to get the VM, stop it, and set it to Generalized:
# Shutdown Source VM & Generalize
$SourceVM = Get-AzureRmVM -ResourceGroupName $SourceRsg -Name $SourceVMName
$Null = Stop-AzureRMVM -ResourceGroupName $SourceRsg -Name $SourceVMName -Force
Write-Host 'Stopped Source VM'
Set-AzureRmVm -ResourceGroupName $SourceRsg -Name $SourceVMName -Generalized
Write-Host 'Set Source VM to Generalized'
I have noticed that when the last command is ran, the output is:
OperationId :
Status :
StartTime :
EndTime :
Error :
It doesn't actually say if it was successful or not?
After this I create the Image from the VM disk.
It might be caused by the image not being "Generalized".
Take a look at the Create a managed image of a generalized VM in Azure guide.
Hope it helps!
If you have a specialized image, the Computer name will be missing because the old computer name and the new computer name share the same RID and SID number and on a ideal situation each virtual machine deployment has different RID and SID number. The Computer name can be displayed if the image is a generalized.
Check this article for more information:
https://learn.microsoft.com/en-us/azure/virtual-machines/windows/create-vm-specialized
https://learn.microsoft.com/en-us/azure/virtual-machines/windows/capture-image-resource
The point everyone is trying to make, from your description of the issue, it seems the Image was not generalized correctly or aspect of the generalization failed.
The script work fine on my end, so the only issue is with the image. Screenshot
Try another deployment from that image an see is you get the same computer name (WIN-I80O6J22ENS).
If you get the same name that is a sure confirmation of issue with generalization.
If the name changes it might mean that the machine you imaged has a policy that is not accepting the name 'dor' so the system is generating default name.
Either way issue is not with the Powershell or Azure. Hope this helps.

How to revert an azure disk back to its former snapshot?

I have a VM in azure, and via the portal have selected its Disk, and created a snapshot of it. How do I now revert back to that snapshot for the Disk (via portal or CLI)?
I'm not looking to create new disks or VMs from the snapshot, just revert back.
How do I now revert back to that snapshot for the Disk (via portal or
CLI)?
Do you mean you want to use this snapshot to rollback your system?
Unfortunately, for now Azure does not support this, we can't use snapshot to revert back.
In Azure, we can't revert back Azure VM directly, we should create disk or VM from that snapshot.
By default, snapshot used for Azure backup. In Azure recovery services, we can restore VMs from the snapshot. Restore this VM was create a new VM with this OS disk, not rollback.
This worked for eastus zone 1 using the cloud shell in the azure portal
$SnapshotName = "my_snapshot"
$SnapshotResourceGroup = "my_resource_group"
$DiskNameOS = "my_new_snapshotdisk"
$snapshotinfo = Get-AzSnapshot -ResourceGroupName $SnapshotResourceGroup -SnapshotName $snapshotName
New-AzDisk -DiskName $DiskNameOS (New-AzDiskConfig -zone 1 -Location eastus -CreateOption Copy -SourceResourceId $snapshotinfo.Id) -ResourceGroupName $SnapshotResourceGroup
After that I went to the VM in the portal, selected "disks" and selected "swap os disk".
I did it successfully with Azure PowerShell, using Set-AzVMOSDisk. There is a module which unfortunately can only restore the snapshots that it created, but its code demonstrates how it works.
Summarised:
Get-AzSnapshot -ResourceGroupName "..." # to find the Disk ID
$vm = Get-AzVM -Name "..."
$old_disk = Get-AzDisk -Name $vm.StorageProfile.OsDisk.name
$diskconf = New-AzDiskConfig -AccountType $old_disk.sku.name -Location $old_disk.Location -SourceResourceId "Id of the disk" -CreateOption Copy
$newdisk = NewAzDisk -Disk $diskconf -ResourceGroupName "..." -DiskName "OS_disk_$((New-Guid).ToString())"
Set-AzVMOSDisk -VM $vm -ManagedDiskId $newdisk.Id -Name $newdisk.Name
Update-AzVM -ResourceGroupName "..." -VM $vm
I did it with the PS script below. It stops VM, creates a new disk using the snapshot, and then swaps VM to this new disk. Snapshot has been created on stopped VM.
$resourceGroupName = '...'
$location = 'eastus2'
$vmName = '...'
$snapshotName = '...'
$snapshotinfo = Get-AzSnapshot -ResourceGroupName $resourceGroupName -SnapshotName $snapshotName
$vm = Get-AzVM `
-ResourceGroupName $resourceGroupName `
-Name $vmName
Stop-AzVM -ResourceGroupName $resourceGroupName -Name $vm.Name -Force
# Create the new disk that you want to swap in
$newDiskName = $($vmName + "_disk_" + (Get-Date).ToString("yyyyMMddhhmm"))
$newDisk = New-AzDisk -DiskName $newDiskName (New-AzDiskConfig -zone 1 -Location $location -CreateOption Copy -SourceResourceId $snapshotinfo.Id) -ResourceGroupName $resourceGroupName
Set-AzVMOSDisk -VM $vm -ManagedDiskId $newDisk.Id -Name $newDisk.Name
Update-AzVM -ResourceGroupName $resourceGroupName -VM $vm
Start-AzVM -Name $vm.Name -ResourceGroupName $resourceGroupName

Adding additional NICs to a Virtual Machine in Azure?

Is it true, that even for Virtual Machine's created in the latest platform (ARM), that if you initially created the machine with 1 NIC, that there is no way to add additional NICs to the VM?
I found a few random (non-Microsoft) articles that seem to indicate this is the case, which if so... is kind of retarded.
So I wanted to make sure that I'm understanding this correctly.
If I have to start all over and build a new machine just to add a NIC, I might consider just using Amazon AWS as I can't imagine this being a limitation over there.
that if you initially created the machine with 1 NIC, that there is no
way to add additional NICs to the VM
It is true, there is no way to add a NIC to an existing VM, and we can't via portal to create a VM with multiple NICs. But we can create/recreate the VM via powershell and add another NIC to it. Here is the powershell script:
$rg = "jason-newgroup"
$loc = "japan east"
$nic01 = "nic01"
$nic02 = "nic02"
$vnet = Get-AzureRmVirtualNetwork -Name ‘jason-newgroup-vnet’ -ResourceGroupName ‘jason-newgroup’
$sub01id = (Get-AzureRmVirtualNetworkSubnetConfig -Name ‘sub01’ -VirtualNetwork $vnet).Id
$sub02id = (Get-AzureRmVirtualNetworkSubnetConfig -Name ‘sub02’ -VirtualNetwork $vnet).Id
$ip1 = '10.1.0.5'
$ip2 = '10.1.1.5'
$nic1 = New-AzureRmNetworkInterface -Name $nic01 -ResourceGroupName $rg -Location $loc -SubnetId $sub01id -PrivateIpAddress $ip1
$nic2 = New-AzureRmNetworkInterface -Name $nic02 -ResourceGroupName $rg -Location $loc -SubnetId $sub02id -PrivateIpAddress $ip2
$vmsize = "Standard_DS4_v2"
$vmname = "jason-windows"
$vm = New-AzureRmVMConfig -VMName $vmname -VMSize $vmsize
$VM = Add-AzureRmVMNetworkInterface -VM $VM -Id $nic1.Id -Primary
$VM = Add-AzureRmVMNetworkInterface -VM $VM -Id $nic2.Id
$osDiskName = "jason-newtest"
$osDiskVhdUri = "https://jasonnewgroupdisks717.blob.core.windows.net/vhds/jason-windows2016920165635.vhd"
$vm = Set-AzureRmVMOSDisk -VM $vm -VhdUri $osDiskVhdUri -name $osDiskName -CreateOption attach -windows
New-AzureRmVM -ResourceGroupName $rg -Location $loc -VM $vm
Notice:
The VM size determines the number of NICS that you can create for a VM. More information about how many NICS each VM size supports, please refer to the link below:
https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-sizes/
There is an update to this. You can now add nics to existing Azure VMs. See the documentation here for tutorial - https://learn.microsoft.com/en-us/azure/virtual-network/virtual-network-network-interface-vm

NewAzureRmVM: Required parameter 'networkProfile' is missing (null)

So I have been trying to create a VM from Linux VHD and getting this error.
Following this
https://pebkac.io/2016/10/mikrotik-chr-in-azure-part-two/
Dinesh has resolved the problem, per comments on this.
It seems that the NIC creation may have been long running.
According to your error, please ensure NIC Interface is created successful.
$InterfaceName = "nic-chr-test"
$Interface = Get-AzureRmNetworkInterface -Name $InterfaceName -ResourceGroupName
You could the result of $Interface, if this is NULL, please create NIC firstly.
Also, you could try to use this template or scripts in this
template.
[Worked for me , needed to add the network interface to vm. Here is the cmdlet
Assuming you already created $nic - network interface earlier
PS C:\azure> $vm = Add-azurermvmnetworkinterface -vm $vm -id $nic.id
PS C:\azure> new-azurermvm -resourcegroupname $rgname -location $location -vm $vm
Add the NW interface for the VM
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic.id

Reducing size of Azure VM OS Disk for download/export

I would like to create an Azure VM with a smaller OS disc than the default 127gb. I've been unable to find such an option in the Azure Portal, so I have attempted to shrink the disk. I have not been successful.
I understand I can trim (using the defragmentation tool) and shrink the volume (with Disk Management) but this won't change the "physical" size of the hard disk. That is, if I shrink the disk to 40gb, there will just be 87gb unallocated and the blob will still report 127gb.
What I am attempting to achieve is to shrink the blob to match the allocated space facilitating smaller downloads/exports of the VM image (e.g. 40 vs 127gb).
Any and all help is appreciated.
I have written a blog post detailing this answer in full. But the main issue here was being able to reduce the size of the Azure VM which defaults to 127gb in order to allow for fasted export/download. The way I have achieved this is by trimming the hard drive and then using Disk2VHD to create a VHD file of the running VM. Disk2VHD will create an expandable disk that is only as large as the current data on the disc, not the entire available disk. In my case 40gb vs 127gb. If one saves this VHD file to an attached disk (read: blob storage) it can be easily downloaded via HTTP by your entire team. Thus, the download is now 40gbs instead of 127gbs. For more, please read my detailed blog post:
http://www.kevinmcloutier.com/?p=263
Original link no longer works:
https://web.archive.org/web/20161027213258/http://kevinmcloutier.com/post/4
In Azure if you create a VM it will create with some default configuration. At present it is not supported to reduce/shrink the OS disk (managed or unmanaged) size of an Azure VM from the Azure Portal (say from 128Gb to 32Gb for example), using the following process we can archive that, and cut down the disk cost.
Step 1. Open your VM and go to the Disk Management.
Step 2. Open PowerShell and execute the following command.
After successful execution you can find the following
Step 3. Now deallocate the VM from the Azure portal
Step 4. Now Go the Properties blade of the disk and copy the Resource ID
Step 5. Now execute the following PowerShell script from your local system. Must change $DiskID, $VMName, $AzSubscription with your value
# Variables
$DiskID = ""# eg. "/subscriptions/203bdbf0-69bd-1a12-a894-a826cf0a34c8/resourcegroups/rg-server1-prod-1/providers/Microsoft.Compute/disks/Server1-Server1"
$VMName = "VM-Server1"
$DiskSizeGB = 32
$AzSubscription = "Prod Subscription"
# Script
# Provide your Azure admin credentials
Connect-AzAccount
#Provide the subscription Id of the subscription where snapshot is created
Select-AzSubscription -Subscription $AzSubscription
# VM to resize disk of
$VM = Get-AzVm | ? Name -eq $VMName
#Provide the name of your resource group where snapshot is created
$resourceGroupName = $VM.ResourceGroupName
# Get Disk from ID
$Disk = Get-AzDisk | ? Id -eq $DiskID
# Get VM/Disk generation from Disk
$HyperVGen = $Disk.HyperVGeneration
# Get Disk Name from Disk
$DiskName = $Disk.Name
# Get SAS URI for the Managed disk
$SAS = Grant-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $DiskName -Access 'Read' -DurationInSecond 600000;
#Provide the managed disk name
#$managedDiskName = "yourManagedDiskName"
#Provide Shared Access Signature (SAS) expiry duration in seconds e.g. 3600.
#$sasExpiryDuration = "3600"
#Provide storage account name where you want to copy the snapshot - the script will create a new one temporarily
$storageAccountName = "shrink" + [system.guid]::NewGuid().tostring().replace('-','').substring(1,18)
#Name of the storage container where the downloaded snapshot will be stored
$storageContainerName = $storageAccountName
#Provide the key of the storage account where you want to copy snapshot.
#$storageAccountKey = "yourStorageAccountKey"
#Provide the name of the VHD file to which snapshot will be copied.
$destinationVHDFileName = "$($VM.StorageProfile.OsDisk.Name).vhd"
#Generate the SAS for the managed disk
#$sas = Grant-AzureRmDiskAccess -ResourceGroupName $resourceGroupName -DiskName $managedDiskName -Access Read -DurationInSecond $sasExpiryDuration
#Create the context for the storage account which will be used to copy snapshot to the storage account
$StorageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName -SkuName Standard_LRS -Location $VM.Location
$destinationContext = $StorageAccount.Context
$container = New-AzStorageContainer -Name $storageContainerName -Permission Off -Context $destinationContext
#Copy the snapshot to the storage account and wait for it to complete
Start-AzStorageBlobCopy -AbsoluteUri $SAS.AccessSAS -DestContainer $storageContainerName -DestBlob $destinationVHDFileName -DestContext $destinationContext
while(($state = Get-AzStorageBlobCopyState -Context $destinationContext -Blob $destinationVHDFileName -Container $storageContainerName).Status -ne "Success") { $state; Start-Sleep -Seconds 20 }
$state
# Revoke SAS token
Revoke-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $DiskName
# Emtpy disk to get footer from
$emptydiskforfootername = "$($VM.StorageProfile.OsDisk.Name)-empty.vhd"
# Empty disk URI
#$EmptyDiskURI = $container.CloudBlobContainer.Uri.AbsoluteUri + "/" + $emptydiskforfooter
$diskConfig = New-AzDiskConfig `
-Location $VM.Location `
-CreateOption Empty `
-DiskSizeGB $DiskSizeGB `
-HyperVGeneration $HyperVGen
$dataDisk = New-AzDisk `
-ResourceGroupName $resourceGroupName `
-DiskName $emptydiskforfootername `
-Disk $diskConfig
$VM = Add-AzVMDataDisk `
-VM $VM `
-Name $emptydiskforfootername `
-CreateOption Attach `
-ManagedDiskId $dataDisk.Id `
-Lun 63
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
$VM | Stop-AzVM -Force
# Get SAS token for the empty disk
$SAS = Grant-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername -Access 'Read' -DurationInSecond 600000;
# Copy the empty disk to blob storage
Start-AzStorageBlobCopy -AbsoluteUri $SAS.AccessSAS -DestContainer $storageContainerName -DestBlob $emptydiskforfootername -DestContext $destinationContext
while(($state = Get-AzStorageBlobCopyState -Context $destinationContext -Blob $emptydiskforfootername -Container $storageContainerName).Status -ne "Success") { $state; Start-Sleep -Seconds 20 }
$state
# Revoke SAS token
Revoke-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername
# Remove temp empty disk
Remove-AzVMDataDisk -VM $VM -DataDiskNames $emptydiskforfootername
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
# Delete temp disk
Remove-AzDisk -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername -Force;
# Get the blobs
$emptyDiskblob = Get-AzStorageBlob -Context $destinationContext -Container $storageContainerName -Blob $emptydiskforfootername
$osdisk = Get-AzStorageBlob -Context $destinationContext -Container $storageContainerName -Blob $destinationVHDFileName
$footer = New-Object -TypeName byte[] -ArgumentList 512
write-output "Get footer of empty disk"
$downloaded = $emptyDiskblob.ICloudBlob.DownloadRangeToByteArray($footer, 0, $emptyDiskblob.Length - 512, 512)
$osDisk.ICloudBlob.Resize($emptyDiskblob.Length)
$footerStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList (,$footer)
write-output "Write footer of empty disk to OSDisk"
$osDisk.ICloudBlob.WritePages($footerStream, $emptyDiskblob.Length - 512)
Write-Output -InputObject "Removing empty disk blobs"
$emptyDiskblob | Remove-AzStorageBlob -Force
#Provide the name of the Managed Disk
$NewDiskName = "$DiskName" + "-new"
#Create the new disk with the same SKU as the current one
$accountType = $Disk.Sku.Name
# Get the new disk URI
$vhdUri = $osdisk.ICloudBlob.Uri.AbsoluteUri
# Specify the disk options
$diskConfig = New-AzDiskConfig -AccountType $accountType -Location $VM.location -DiskSizeGB $DiskSizeGB -SourceUri $vhdUri -CreateOption Import -StorageAccountId $StorageAccount.Id -HyperVGeneration $HyperVGen
#Create Managed disk
$NewManagedDisk = New-AzDisk -DiskName $NewDiskName -Disk $diskConfig -ResourceGroupName $resourceGroupName
$VM | Stop-AzVM -Force
# Set the VM configuration to point to the new disk
Set-AzVMOSDisk -VM $VM -ManagedDiskId $NewManagedDisk.Id -Name $NewManagedDisk.Name
# Update the VM with the new OS disk
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
$VM | Start-AzVM
start-sleep 180
# Please check the VM is running before proceeding with the below tidy-up steps
# Delete old Managed Disk
Remove-AzDisk -ResourceGroupName $resourceGroupName -DiskName $DiskName -Force;
# Delete old blob storage
$osdisk | Remove-AzStorageBlob -Force
# Delete temp storage account
$StorageAccount | Remove-AzStorageAccount -Force
You would have to create your own VM image and then deploy using that. This template shows you how to deploy using your own image.
https://github.com/Azure/azure-quickstart-templates/tree/master/101-vm-from-user-image
Currently, the images in the gallery are all 127gb. Since Azure VMs only used fixed size discs, you can't just select the size.
Sapnandu's solution works. Many thanks!
I'm still not 100% sure what was the magic criteria to make it work, but finally I have a vm running with the reduced disk. Making it Gen1 definitely was one.
I tried many similar things and they all got stuck at boot time.
My way was:
Create the vm from the gallery images. You'll have a 128Gb OS disk.
Tweak the vm according to your needs. Here you can run the resize script. So, you'll end up with a ~90Gb unallocated space.
After a few failed attempts I started to value the configured vm and I really didn't want to repeat the configuration again.
Make a snapshot of this disk then make a disk from the snapshot. These options will be presented to you by the snapshot and by the disk.
Then make a new vm from the disk. Check if it boots. Boot diagnostics shows it rather quickly.
After stopping the new vm I looked up the 3 (subscriptionID,diskID,vmName) required parameters for Sapnandu's script (Step 5. in his post) and executed the script in azure cloud shell. (the icon in header)
It takes time, about 10 minutes or so.
When the script finished the new vm was running with the smaller disk.
So, there is a vm setup where the script works perfectly.

Resources