[Azure]ARM模式下删除虚拟机挂盘修复后恢复的脚本(托管磁盘)

60 篇文章 0 订阅
59 篇文章 0 订阅

使用Azure虚拟机经常会遇到无法连接的问题,比如我们修改了虚拟机防火墙,修改了注册表,修改了配置文件,系统磁盘文件系统挂掉了等等。

遇到这种问题的时候,由于Azure没有开放控制台登录虚拟机的功能,所以只能将原来的虚拟机以保留磁盘的方式删除掉,然后将系统磁盘挂载到其他机器上修复各种问题,再使用修复后的磁盘重新创建出虚拟机来。

对于经典虚拟机(ASM)来说,挂盘后的重建可以通过界面完成,但是ARM虚拟机目前使用vhd创建的话,只能通过Azure Powershell进行,而且很多虚拟机的创建参数都需要提前记录下来,包括数据磁盘,网卡等都要在重建的过程中依次配好,对于没有使用过Azure Powershell的用户来说,可能难度比较大一些。

下面这个脚本提供了一个非常方便的功能,脚本首先会收集指定虚拟机的信息并输出到屏幕,然后我们输入continue后,脚本会将这台虚拟机删除掉,删除掉之后,脚本会等待用户输入,这个时候,就可以将保留下来的磁盘挂载到其他机器上修复了,修复完成后,将磁盘分离下来,然后按Enter键继续执行脚本,脚本会再利用原来的磁盘将虚拟机还原回来。

这个脚本针对的是托管磁盘的虚拟机。

脚本如下:

param(
    [Parameter(Mandatory = $true)] 
    [string]$SubscriptionName, 
 
    [Parameter(Mandatory = $true)]
    [string]$ResourceGroupName,

    [Parameter(Mandatory = $true)]
    [string]$VMName
)

Function GetResourceNameFromResourceId($resourceId)
{
    return $resourceId.Substring($resourceId.LastIndexOf('/') + 1);
}

Function GetResourcePropertyFromResourceId($resourceId, $propertyName)
{
    $propertyName = $propertyName + "/";
    $rgName = $resourceId.Substring($resourceId.IndexOf($propertyName) + $propertyName.Length);
    return $rgName.Substring(0, $rgName.IndexOf("/"));
}

Function CollectVMInformation($rgName, $vmName)
{
    $vmInfo = @{};
    $vmInfo.Add("ResourceGroup", $rgName);
    $vmInfo.Add("Name", $vmName);
    
    $vm = Get-AzureRmVM -ResourceGroupName $rgName -Name $vmName -ErrorAction Ignore -WarningAction Ignore;
    if ($vm -eq $null)
    {
        return $null;
    }

    $vmInfo.Add("Size", $vm.HardwareProfile.VmSize);
    $vmInfo.Add("Location", $vm.Location);
    if ($vm.AvailabilitySetReference -ne $null)
    {
        $vmInfo.Add("AvailabilitySet", $vm.AvailabilitySetReference.Id);
    }

    $vmInfo.Add("OSType", $vm.StorageProfile.OsDisk.OsType.ToString());

    #network properties
    $nicId = ($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $true}).Id;
    if ($nicId -eq $null -and $vm.NetworkProfile.NetworkInterfaces.Count -eq 1)
    {
        $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id;
    }
    $vmInfo.Add("PrimaryNetworkInterfaceId", $nicId);

    $secondaryNics = @($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $false});
    $vmInfo.Add("SecondaryNetworkInterfaces", $secondaryNics);

    #disk
    $vmInfo.Add("OSDisk", $vm.StorageProfile.OsDisk);
    $vmInfo.Add("DataDisks", @($vm.StorageProfile.DataDisks));

    Write-Host ("{0, -16}: {1}" -f "Name", $vmInfo["Name"]) -ForegroundColor Cyan;
    Write-Host ("{0, -16}: {1}" -f "Resource Group", $vmInfo["ResourceGroup"]) -ForegroundColor Cyan;
    Write-Host ("{0, -16}: {1}" -f "Size", $vmInfo["Size"]) -ForegroundColor Cyan;
    Write-Host ("{0, -16}: {1}" -f "Location", $vmInfo["Location"]) -ForegroundColor Cyan;
    Write-Host ("{0, -16}: {1}" -f "OS Type", $vmInfo["OSType"]) -ForegroundColor Cyan;
    if ($vmInfo.ContainsKey("AvailabilitySet"))
    {
        Write-Host ("{0, -16}: {1}" -f "Availability Set", $vmInfo["AvailabilitySet"]) -ForegroundColor Cyan;
    }
    Write-Host ("{0, -16}: {1}" -f "Primary NIC", $vmInfo["PrimaryNetworkInterfaceId"]) -ForegroundColor Cyan;
    foreach ($secondaryNic in $vmInfo["SecondaryNetworkInterfaces"])
    {
        Write-Host ("{0, -16}: {1}" -f "Secondary NIC", $secondaryNic.Id) -ForegroundColor Cyan;
    }
    Write-Host ("{0, -16}: {1}" -f "OS Disk", $vmInfo["OSDisk"].Name) -ForegroundColor Cyan;
    foreach ($dataDisk in $vmInfo["DataDisks"])
    {
        Write-Host ("{0, -16}: {1}" -f "Data Disk", $dataDisk.Name) -ForegroundColor Cyan;
    }

    return $vmInfo;
}

Function DeleteOldVM($rgName, $vmName)
{
    [void](Remove-AzureRmVM -ResourceGroupName $rgName -Name $vmName -Force);
    #if lease is not broken, we need to sleep for some time
    #sleep 10
}

Function RebuildVM($vmInfo)
{
    #basic information
    $rgName = $vmInfo["ResourceGroup"];
    $vmName = $vmInfo["Name"];
    $vmSize = $vmInfo["Size"];
    $location = $vmInfo["Location"];
    $osType = $vmInfo["OSType"];

    #network
    $primaryNicId = $vmInfo["PrimaryNetworkInterfaceId"];
    $secondaryNics = $vmInfo["SecondaryNetworkInterfaces"];
    
    #disk
    $osDisk = $vmInfo["OSDisk"];
    $dataDisks = $vmInfo["DataDisks"];

    $vmconfig = $null;
    if ($vmInfo.ContainsKey("AvailabilitySet"))
    {
        $avaSetId = $vmInfo["AvailabilitySet"];
        $vmconfig = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize -AvailabilitySetId $avaSetId;
    }
    else
    {
        $vmconfig = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize;
    }
    $vmconfig = $vmconfig | Set-AzureRmVMBootDiagnostics -Disable;

    if ($osType -eq "Windows")
    {
        $vmconfig = $vmconfig | Set-AzureRmVMOSDisk -ManagedDiskId $osDisk.ManagedDisk.Id -Caching $osDisk.Caching -CreateOption attach -Windows;
    } else {
        $vmconfig = $vmconfig | Set-AzureRmVMOSDisk -ManagedDiskId $osDisk.ManagedDisk.Id -Caching $osDisk.Caching -CreateOption attach -Linux;
    }
    #下面这个步骤是必须要有而且非常重要的,实测下来发现上面的命令有个小bug,就是托管磁盘添加后,磁盘名默认会被设置成虚拟机名称
    #导致创建的时候报错“New-AzureRmVM : Changing property 'osDisk.name' is not allowed”
    $vmconfig.StorageProfile.OsDisk.Name = $osDisk.Name;
    $vmconfig.StorageProfile.ImageReference = $null;

    $index = 0;
    foreach ($dataDisk in $dataDisks)
    {
        $vmconfig = $vmconfig | Add-AzureRmVMDataDisk -ManagedDiskId $dataDisk.ManagedDisk.Id -Lun $dataDisk.Lun -Caching $dataDisk.Caching -CreateOption attach;
        #下面这个步骤是必须要有而且非常重要的,实测下来发现上面的命令有个小bug,就是托管磁盘添加后,磁盘名默认会被设置成虚拟机名称
        #导致创建的时候报错“New-AzureRmVM : Changing property 'dataDisk.name' is not allowed”
        $vmconfig.StorageProfile.DataDisks[$index].Name = $dataDisk.Name;
        $index += 1;
    }

    $vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $primaryNicId -Primary;
    foreach ($secondaryNic in $secondaryNics)
    {
        $secondaryNicId = $secondaryNic.Id;
        $vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $secondaryNicId;
    }

    [void](New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vmconfig);
}

[void](Select-AzureRmSubscription -SubscriptionName $SubscriptionName);

Write-Host "Virtual Machine information before deletion:" -ForegroundColor Green;
$vmInfo = (CollectVMInformation $ResourceGroupName $VMName);
if ($vmInfo -eq $null)
{
    Write-Host "Failed to collect vm information." -ForegroundColor Red;
    return;
}

If ((Read-Host "Enter 'continue' to delete VM") -ne "continue")
{
    Write-Host "Canceled" -ForegroundColor Yellow;
    return;
}

Write-Host "Deleting old VM..." -ForegroundColor Yellow;
DeleteOldVM $ResourceGroupName $VMName;

Write-Host "VM deleted" -ForegroundColor Yellow;
Read-Host "Press enter to rebuild VM";

Write-Host "Rebuilding VM..." -ForegroundColor Yellow;
RebuildVM $vmInfo;
Write-Host "Virtual Machine information after rebuild:" -ForegroundColor Green;
[void](CollectVMInformation $ResourceGroupName $VMName);

Write-Host "Finished" -ForegroundColor Yellow;

执行结果:


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值