在《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
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

