PowerShell批量导出Azure中的磁盘镜像到存储账户


在《PowerShell批量给Azure虚拟机磁盘创建镜像 》一文中,我们创建磁盘镜像的目的是为了把它导出到灾备数据中心的存储账户中。因为Azure上单台虚拟机的网络峰值限制,如果磁盘太多,建议使用多台虚拟机进行分组复制。在一台机器上,复制多块磁盘,也可以使用多线程批量操作。

本文最大的亮点在于如何把PowerShell子线程的复制Azure磁盘的进度关键信息,实时读取到主控台,并且在主控台通过进度条展示,我们先欣赏一下进度条截图,挺酷的吧!

下面贴出演示脚本:

 $diskConfig = Get-Content .\vm-disk.config -Raw  | ConvertFrom-Json


 $diskRG = "{资源组名称}"
 $storageAccount = '{存储账户名称}'
 $storageKey = '{存储账户秘钥}'
 $containnerName = "{存储账户容器名称}"
 $storageContext = New-AzureStorageContext `
    –StorageAccountName $storageAccount `
    -StorageAccountKey $storageKey  `
    -Environment AzureChinaCloud

 Write-Output "配置文件中,共检测到$($diskConfig.Count)个磁盘"
 
 $sb = {
  param(
      $cfg,
      $diskRG,
      $storageContext,
      $containnerName)

  
      Write-Output "正在申请镜像【$($cfg.Name)】 的SAS.."
      Write-Output "Grant-AzureRmSnapshotAccess -ResourceGroupName $diskRG -Access Read -SnapshotName $($cfg.ImageId) -DurationInSecond 3600"
      $sas = Grant-AzureRmSnapshotAccess -ResourceGroupName $diskRG -Access Read -SnapshotName $cfg.ImageId -DurationInSecond 3600
      if($sas -eq $null){
        Write-Output "sas 申请失败"
        return
      }
      Write-Output "sas.AccessSAS=$($sas.AccessSAS)"
      
      Write-Output "镜像【$($cfg.Name)】 的SAS申请完毕"

      $vhdName = $cfg.imageId+".vhd"

      Write-Output "镜像【$($cfg.Name)】 的复制已启动"
      Start-AzureStorageBlobCopy `
        -AbsoluteUri $sas.AccessSAS `
        -DestContainer $containnerName `
        -DestContext $storageContext `
        -DestBlob $vhdName `
        -Confirm:$false -Force #| Out-Null
        

    Write-Output "镜像【$($cfg.Name)】 的复制正在进行中"
      Get-AzureStorageBlobCopyState `
      -Context $storageContext `
      -Container $containnerName `
      -Blob $vhdName -WaitForComplete #|  Out-Null
     
    Write-Output "镜像【$($cfg.Name)】 的复制已完成"
  }
 
    $jobs = @()    
   foreach ($cfg in $diskConfig)
   {
      $job=[PowerShell]::Create()
      $job = $job.AddScript($sb);
      $job = $job.AddParameter("cfg",$cfg)
      $job = $job.AddParameter("diskRG",$diskRG)
      $job = $job.AddParameter("storageContext",$storageContext)
      $job = $job.AddParameter("containnerName",$containnerName)
       
      Write-Output "复制磁盘【$($cfg.Name)】镜像的Job已启动"
      $jobs += New-Object PSObject -Property @{
        cfg = $cfg
        Task = $job
        Result = $job.BeginInvoke()
      }
 
   }

# 打印磁盘复制进度
$runningJobs = $jobs.Count
$tc = New-Object System.Diagnostics.Stopwatch
$tc.Start()
$copyElapsed = ""
while($runningJobs -gt 0){
    $runningJobs = ($jobs | where { $_.Task.InvocationStateInfo.State -eq [System.Management.Automation.PSInvocationState]::Running } ).Count
    if($runningJobs -gt 0){
        
        # 总进度
        $finishedCount = $jobs.Count - $runningJobs
        $totalProgressPercent = [int]($finishedCount * 100/$jobs.Count)
        $copyElapsed = $tc.Elapsed.TotalMinutes.ToString("0.00")
        Write-Progress -Activity "复制磁盘总进度,已用时 $copyElapsed 分钟" -Status "已完成:$finishedCount, 剩余: $runningJobs" -Id ([int]::MaxValue) -PercentComplete $totalProgressPercent

        # 子进度
        for($index = 0;$index -lt $jobs.Length;$index++)
        {
            $job = $jobs[$index]
            $subProgressPercent = 0
            if($job.Task.Streams.Progress[-1].StatusDescription -match 'Percent:(?<Percent>.*)%.'){
                $subProgressPercent = $Matches.Percent
            }
            $vmName = $job.cfg.VmName
            $diskName = $job.cfg.Name
            Write-Progress -Activity "复制虚拟机[$vmName] 的磁盘 [$diskName]" -Status "已完成 $subProgressPercent%" -Id ($index+1) -ParentId ([int]::MaxValue) -PercentComplete $subProgressPercent

        }
        sleep -Milliseconds 250
    }

}


Write-Output "所有Job已执行完毕,输出如下:"
ForEach ($job in $jobs)
{
    $job.Task.EndInvoke($job.Result)
}
$tc.Stop()
Write-Output "复制总耗时:$copyElapsed 分钟"
本文链接: https://www.pstips.net/batch-export-vm-images-to-storage-account.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

关于 Mooser Lee

我是一个Powershell的爱好者,创建了PowerShell中文博客,热衷于Powershell技术的搜集和分享。本站部分内容来源于互联网,不足之处敬请谅解,并欢迎您批评指正。

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注