ARM模式下對多磁盤虛擬機捕獲映像再批量創建需要對磁盤進行一般化操作,然後使用模板進行創建,整個過程比較複雜,因此爲了簡化操作,整理了一個用於克隆虛擬機的腳本。
特別針對多網卡虛擬機以及網卡多IP的情況進行了邏輯處理。但是對於診斷等設置沒有進行克隆。
注意這個腳本針對非託管磁盤的虛擬機。
腳本如下:
param(
[Parameter(Mandatory = $true)]
[string]$SubscriptionName,
[Parameter(Mandatory = $true)]
[string]$ResourceGroupName,
[Parameter(Mandatory = $true)]
[string]$VMName,
[Parameter(Mandatory = $true)]
[string]$NewVmName,
[Parameter(Mandatory = $true)]
[string]$VmCount
)
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 GetStorageAccountNameFromVhdUri($vhdUri)
{
$startLength = "https://".Length;
return $vhdUri.Substring($startLength, $vhdUri.IndexOf(".blob.core.chinacloudapi.cn") - $startLength);
}
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"].Vhd.Uri) -ForegroundColor Cyan;
foreach ($dataDisk in $vmInfo["DataDisks"])
{
Write-Host ("{0, -16}: {1}" -f "Data Disk", $dataDisk.Vhd.Uri) -ForegroundColor Cyan;
}
return $vmInfo;
}
Function CopyBlob($sourceVhdUri, $newBlobName)
{
$storageAccountName = GetStorageAccountNameFromVhdUri $sourceVhdUri;
$containerName = GetResourcePropertyFromResourceId $sourceVhdUri ".blob.core.chinacloudapi.cn";
$srcBlobName = GetResourceNameFromResourceId $sourceVhdUri;
$storage = $allStorageAccounts | where {$_.StorageAccountName -eq $storageAccountName};
[void](Start-AzureStorageBlobCopy -SrcBlob $srcBlobName -SrcContainer $containerName -SrcContext $storage.Context -DestBlob $newBlobName -DestContainer $containerName -DestContext $storage.Context);
# check copy status
$state = Get-AzureStorageBlobCopyState -Context $storage.Context -Blob $newBlobName -Container $containerName;
while ($state.Status -ne "Success")
{
sleep 1;
$state = Get-AzureStorageBlobCopyState -Context $storage.Context -Blob $newBlobName -Container $containerName;
}
return ("https://{0}.blob.core.chinacloudapi.cn/{1}/{2}" -f $storageAccountName, $containerName, $newBlobName);
}
Function CopyNic($nicId, $newVmName, $nicIndex)
{
$nicName = GetResourceNameFromResourceId $nicId;
$rgName = GetResourcePropertyFromResourceId $nicId "resourceGroups";
$nic = Get-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $rgName;
$primaryIPCfg = $nic.IpConfigurations | where {$_.Primary -eq $true};
$subnetId = $primaryIPCfg.Subnet.Id;
$subnetName = GetResourceNameFromResourceId $subnetId;
$vnetName = GetResourcePropertyFromResourceId $subnetId "virtualNetworks";
$newNic = $null;
$newNicName = ("{0}NIC{1}" -f $newVmName, $nicIndex);
if ($primaryIPCfg.PublicIpAddress -eq $null)
{
$newNic = New-AzureRmNetworkInterface -Name $newNicName -ResourceGroupName $nic.ResourceGroupName -Location $nic.Location -SubnetId $subnetId -WarningAction Ignore;
}
else
{
$newPrimaryPipName = ("{0}PIP{1}_0" -f $newVmName, $nicIndex);
$primaryPipId = (CopyPip $primaryIPCfg.PublicIpAddress.Id $newPrimaryPipName);
$newNic = New-AzureRmNetworkInterface -Name $newNicName -ResourceGroupName $nic.ResourceGroupName -Location $nic.Location -SubnetId $subnetId -PublicIpAddressId $primaryPipId -WarningAction Ignore;
}
if ($nic.NetworkSecurityGroup -ne $null)
{
$newNic.NetworkSecurityGroup = $nic.NetworkSecurityGroup;
[void]($newNic | Set-AzureRmNetworkInterface);
}
$secondaryIPCfgs = $nic.IpConfigurations | where {$_.Primary -eq $false};
for ($i = 0; $i -lt $secondaryIPCfgs.Count; $i++)
{
$ipCfgName = ("{0}PIP{1}_{2}" -f $newVmName, $nicIndex, ($i+1));
$ipCfg = $null;
if ($secondaryIPCfgs[$i-1].PublicIpAddress -eq $null)
{
$ipCfg = New-AzureRmNetworkInterfaceIpConfig -Name $secondaryIPCfgs[$i-1].Name -SubnetId $subnetId -WarningAction Ignore;
}
else
{
$newPipId = (CopyPip $secondaryIPCfgs[$i-1].PublicIpAddress.Id $ipCfgName);
$ipCfg = New-AzureRmNetworkInterfaceIpConfig -Name $secondaryIPCfgs[$i-1].Name -SubnetId $subnetId -PublicIpAddressId $newPipId -WarningAction Ignore;
}
[void]($newNic.IpConfigurations.Add($ipCfg));
}
[void]($newNic | Set-AzureRmNetworkInterface);
return $newNic.Id;
}
Function CopyPip($pipId, $newPipName)
{
$rgName = GetResourcePropertyFromResourceId $pipId "resourceGroups";
$ipName = GetResourceNameFromResourceId $pipId;
$oldPip = Get-AzureRmPublicIpAddress -Name $ipName -ResourceGroupName $rgName;
$pip = New-AzureRmPublicIpAddress -Name $newPipName -ResourceGroupName $rgName -Location $oldPip.Location -AllocationMethod $oldPip.PublicIpAllocationMethod -WarningAction Ignore;
return $pip.Id;
}
Function CreateNewVm($vmInfo, $vmName)
{
#basic information
$rgName = $vmInfo["ResourceGroup"];
$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;
Write-Host "Cloning disks..." -ForegroundColor Yellow;
$newOsDiskUri = (CopyBlob $osDisk.Vhd.Uri ("{0}_OSDisk.vhd" -f $vmName));
if ($osType -eq "Windows")
{
$vmconfig = $vmconfig | Set-AzureRmVMOSDisk –Name $osDisk.Name -VhdUri $newOsDiskUri -Caching $osDisk.Caching -CreateOption attach -Windows;
} else {
$vmconfig = $vmconfig | Set-AzureRmVMOSDisk –Name $osDisk.Name -VhdUri $newOsDiskUri -Caching $osDisk.Caching -CreateOption attach -Linux;
}
$vmconfig.StorageProfile.ImageReference = $null;
foreach ($dataDisk in $dataDisks)
{
$newDataDiskUri = (CopyBlob $dataDisk.Vhd.Uri ("{0}_DataDisk_{1}.vhd" -f $vmName,$dataDisk.Lun));
$vmconfig = $vmconfig | Add-AzureRmVMDataDisk -Name $dataDisk.Name -VhdUri $newDataDiskUri -Lun $dataDisk.Lun -Caching $dataDisk.Caching -CreateOption attach;
}
Write-Host "Cloning network interfaces..." -ForegroundColor Yellow;
$newPrimaryNicId = (CopyNic $primaryNicId $vmName 0);
$vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $newPrimaryNicId -Primary;
$secondaryNicCount = $secondaryNics.Count;
for ($i = 0; $i -lt $secondaryNicCount; $i++)
{
$secondaryNicId = $secondaryNics[$i].Id;
$newSecondaryNicId = (CopyNic $secondaryNicId $vmName ($i+1));
$vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $newSecondaryNicId;
}
Write-Host "Creating new virtual machine..." -ForegroundColor Yellow;
[void](New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vmconfig);
}
[void](Select-AzureRmSubscription -SubscriptionName $SubscriptionName);
$allStorageAccounts = Get-AzureRmStorageAccount;
Write-Host "Virtual Machine information:" -ForegroundColor Green;
$vmInfo = (CollectVMInformation $ResourceGroupName $vmName);
if ($vmInfo -eq $null)
{
Write-Host "Failed to collect vm information." -ForegroundColor Red;
return;
}
for ($i = 0; $i -lt $VmCount; $i++)
{
$newName = $NewVmName + ($i+1);
Write-Host ("Cloning virtual machine {0}..." -f $newName) -ForegroundColor Yellow;
CreateNewVm $vmInfo $newName;
Write-Host ("Finished cloning virtual machine {0}." -f $newName) -ForegroundColor Green;
}
Write-Host "Finished" -ForegroundColor Green;
運行結果: