【问题标题】:cloning multiple VMs in parallel with multithreaded PowerCLI使用多线程 PowerCLI 并行克隆多个 VM
【发布时间】:2012-05-03 00:19:00
【问题描述】:

我承担了在 VMware 中克隆大量虚拟机的任务。我不想通过克隆向导点击数百次,而是希望尽可能地自动化。

我已经配置并“密封”了模板机。克隆并打开电源后,新克隆的实例将启动,并在其中停留一段时间,然后进行系统准备等。这大约需要 20 分钟左右。

我找到了一个非常好的script over on MSFT TechNet,它可以完成我需要它做的所有事情。我已经对其进行了一些修改,因此我不必更改值并为流程的每个步骤重新保存脚本。而不是整个脚本中的 $Step 计数器,我只是用一些 Start-Sleep 延迟替换它。此时,它工作正常并成功克隆了它从 CSV 文件中读取的所有机器。每台机器大约需要 35 分钟才能准备就绪(机器已移至不同的 AD OU)。

唯一的问题是它全部串行运行,等待整个过程(克隆、更改 VLAN、启动机器并等待域加入,并将最终机器对象移动到不同的 AD OU)完成,然后再开始另一个克隆。

我真正想要的是多线程以使整个操作更快。我在测试中发现,一旦运行大约五个单独的克隆作业,vSphere 中的克隆就会开始减慢,因此我想修改此脚本以同时运行四个克隆(执行整个工作流程)。

有什么想法吗?如果需要,我可以粘贴代码。

【问题讨论】:

    标签: vmware powercli


    【解决方案1】:

    您最多可以从一个模板并行克隆 8 个虚拟机。如果您使用 -RunAsync 运行 new-vm。使用 -RunAsync 命令立即返回,输出由一个或多个 Task 对象组成。

    如果您想克隆多个虚拟机,以下应该会有所帮助。循环一下。

    Write-host "Deploying VM " -ForegroundColor Green -NoNewline; Write-Host $vmname -ForegroundColor Yellow
    get-OScustomizationspec $cs | get-OScustomizationNicMapping | set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $vm.IP -SubnetMask $vm.subnet -DefaultGateway $vm.gateway -Dns $vm.Dns1, $vm.Dns2
    
    $vms = New-VM -Name $vm.Name -Location $vm.cluster -VMhost $vm.vmhost -Template $vm.template -Datastore $vm.datastore -OSCustomizationSpec $cs -confirm:$false **-RunAsync**
    
    if ($vm1.error) {
        Write-Host "Error in deploying $vmname" -ForegroundColor Red
    }
    

    【讨论】:

      【解决方案2】:

      以下是我在过去几天编写的脚本,它将 VM 模板部署到我们大约 650 台服务器。它从全国不同数据中心的 3 个不同的 VM 主机部署它。它同时从欧文部署 5 个,从普莱诺部署 15 个,从亚特兰大部署 15 个。它在周一至周五晚上 7 点至早上 6 点之间以及周六和周日全天运行。如果它在任何其他时间运行,它就会退出。

      当我试图弄清楚在使用 Start-Job 调用该函数时如何将多个参数传递给一个函数时,我没时间了,所以我只是为这三个位置创建了一个单独的函数。

      使用此脚本,我们能够在大约一周的晚上和周末将新的 RDC 映像部署到 650 多个位置。

      参数( [参数(ValueFromPipelineByPropertyName=$true)] [字符串]$InputFile = $null )

      Get-Module -ListAvailable VMware* | Import-Module | Out-Null
      Import-Module ActiveDirectory
      
      $Global:CompletedHosts = @()
      
      $MAXVMHostCount = 50
      $IrvingMaxJobs = 6
      $PlanoMaxJobs = 15
      $AtlantaMaxJobs = 15
      
      Function Add-VMHosts() {
          param(
              [Parameter(Mandatory=$true)][int]$MAXVMHostCount,
              [Parameter(Mandatory=$false)][string]$InputFile
          )
      
          $AllVMHosts = @()
      
          If ($InputFile) {
              $AllVMHosts = Get-Content $InputFile
          }
          Else {
              $Jobs = (Get-Job).Name
              If ($Jobs -ne $null) {
                  $Jobs = $Jobs.Trim("-TXINTATL")
              }
      
              ForEach ($Server in (Get-ADComputer -Server *************** -SearchBase "OU=************************" -Filter { Name -like "**********" })) {
                  If ($Server.Name.Substring(10,1) -eq "0") {
                      $IP = "10." + $Server.Name.Substring(11,1) + "."
                  }
                  Else {
                      $IP = "10." + $Server.Name.Substring(10,2) + "."
                  }
                  If ($Server.Name.Substring(12,2) -eq "00") {
                      $IP += "100"
                  }
                  ElseIf ($Server.Name.Substring(12,1) -eq "0") {
                      $IP += $Server.Name.Substring(13,1)
                  }
                  Else {
                      $IP += $Server.Name.Substring(12,2)
                  }
                  $IP += ".252"
      
                  If ($IP -notin $Global:CompletedHosts -and $IP -notin $Jobs) {
                      $AllVMHosts = $AllVMHosts + $IP
                  }
              }
          }
      
          Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
      
          $CurrentVMHostCount = (Get-VMHost -Location (Get-Datacenter "Profit Centers")).Count
      
          $HostCount = 0
          ForEach ($VMHost in $AllVMHosts) {
              If ($HostCount -ge ($MaxVMHostCount - $CurrentVMHostCount)) {
                  Break
              }
              Else {
                  $AddFailed = $false
                  $ConnectFailed = $false
                  $Test = $null
      
                  $Test = Get-VMHost $VMHost -ErrorAction SilentlyContinue
                  If (!$Test -and (Test-Connection $VMHost -Quiet)) {
                      Try {
                          Connect-VIServer $VMHost -User "********************" -Password "********************" -WarningAction SilentlyContinue | Out-Null
                      }
                      Catch {
                          $ConnectFailed = $true
                      }
      
                      If (!$ConnectFailed -and (Get-VMHost $VMHost -ErrorAction SilentlyContinue | Get-VM -ErrorAction SilentlyContinue | Where { $_.Name -like "*********************" }) -eq $null -and (Test-Connection $VMHost -Quiet)) {
                          Set-VMHost -VMHost $VMHost -LicenseKey "********************" | Out-Null
                          Disconnect-VIServer -Server $VMHost -Confirm:$false | Out-Null
      
                          Add-VMHost $VMHost -Location (Get-DataCenter -Name "Profit Centers") -User "********************" -Password "********************" -Force:$true -ErrorAction SilentlyContinue | Out-Null
                          Start-Sleep -Seconds 5
                          Write-Host "$VMHost added to vCenter successfully"
      
                          $myVMHost = Get-VMHost $VMHost
                          $myVMHost | Get-VirtualPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -InheritLoadBalancingPolicy $true -InheritNetworkFailoverDetectionPolicy $true -InheritNotifySwitches $true -InheritFailback $true -InheritFailoverOrder $true -WarningAction SilentlyContinue | Out-Null
                          $myVMHost | Get-VirtualPortGroup | Get-SecurityPolicy | Set-SecurityPolicy -AllowPromiscuousInherited $true -ForgedTransmitsInherited $true -MacChangesInherited $true | Out-Null
      
                          ForEach ($PortGroup in (Get-VirtualPortGroup -VMHost $VMHost)) {
                              $netSys = Get-View (Get-VMHost -Name $VMHost).ExtensionData.ConfigManager.NetworkSystem
                              $spec = (Get-VirtualPortGroup -Name $PortGroup.Name -VMHost $VMHost).ExtensionData.Spec
                              $spec.Policy.ShapingPolicy.Enabled = $null
                              $netSys.UpdatePortgroup($PortGroup.Name,$spec)
                          }
      
                          $DisconnectedNICs = Get-VMHostNetworkAdapter -VMHost $VMHost -Physical | Where-Object { $_.BitRatePerSec -eq "0" }
                          If (($DisconnectedNICs.Count -gt 0)) {
                              If (($DisconnectedNICs.DeviceName).Contains("vmnic0")) {
                                  $myVMHost | Get-VirtualSwitch -Name vSwitch0 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive vmnic1,vmnic0 | Out-Null
                              }
                          }
                          $HostCount++
                      }
                      ElseIf ($ConnectFailed) {
                          Write-Host "Failed to connect to $VMHost" -ForegroundColor Yellow
                      }
                      Else {
                          Write-Host "$VMHost already has RDC Image" -ForegroundColor Yellow
                          If ($VMHost.Name -notin $Global:CompletedHosts) {
                              $Global:CompletedHosts = $Global:CompletedHosts + $VMHost.Name
                          }
                      }
                  }
                  Else {
                      Write-Host "$VMHost already exists in vCenter" -ForegroundColor Yellow
                  }
              }
          }
      
          Get-AlarmDefinition "Network uplink redundancy lost" -ErrorAction SilentlyContinue | Set-AlarmDefinition -Enabled $false | Out-Null
          Get-AlarmDefinition "Network uplink redundancy lost" -ErrorAction SilentlyContinue | Set-AlarmDefinition -Enabled $true | Out-Null
      
          Disconnect-VIServer -Server * -Confirm:$false
      }
      
      Function CopyVMToHostIrving([string]$VMHost) {
      
          Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
      
          If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
              $NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
      
              New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-TX" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
      
              Start-Sleep -Seconds 10
              Start-VM $NewVMName | Out-Null
              Start-Sleep -Seconds 5
      
              If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
                  Exit
              }
      
              Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
                  If ($DCstartedEvent) {
                      Break
                  }
                  Else {
                      Start-Sleep -Seconds 5
                  }
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
                  $DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
                  If ($DCFailureEvent) {
                      Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
                      Break
                  }
                  If ($DCSucceededEvent) {
                      Break
                  }
                  Start-Sleep -Seconds 5
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
      
              Start-Sleep -Seconds 30
              Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
              Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
              Start-Sleep -Seconds 30
      
              Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
          }
      
          Disconnect-VIServer -Server * -Confirm:$false
      }
      
      Function CopyVMToHostPlano([string]$VMHost) {
      
          Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
      
          If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
              $NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
      
              New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-INT" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
      
              Start-Sleep -Seconds 10
              Start-VM $NewVMName | Out-Null
              Start-Sleep -Seconds 5
      
              If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
                  Exit
              }
      
              Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
                  If ($DCstartedEvent) {
                      Break
                  }
                  Else {
                      Start-Sleep -Seconds 5
                  }
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
                  $DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
                  If ($DCFailureEvent) {
                      Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
                      Break
                  }
                  If ($DCSucceededEvent) {
                      Break
                  }
                  Start-Sleep -Seconds 5
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
      
              Start-Sleep -Seconds 30
              Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
              Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
              Start-Sleep -Seconds 30
      
              Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
          }
      
          Disconnect-VIServer -Server * -Confirm:$false
      }
      
      Function CopyVMToHostAtlanta([string]$VMHost) {
      
          Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
      
          If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
              $NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
      
              New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-ATL" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
      
              Start-Sleep -Seconds 10
              Start-VM $NewVMName | Out-Null
              Start-Sleep -Seconds 5
      
              If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
                  Exit
              }
      
              Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
                  If ($DCstartedEvent) {
                      Break
                  }
                  Else {
                      Start-Sleep -Seconds 5
                  }
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
              While($True) {
                  $DCvmEvents = Get-VIEvent -Entity $NewVMName
                  $DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
                  $DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
                  If ($DCFailureEvent) {
                      Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
                      Break
                  }
                  If ($DCSucceededEvent) {
                      Break
                  }
                  Start-Sleep -Seconds 5
              }
      
              Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
      
              Start-Sleep -Seconds 30
              Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
              Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
              Start-Sleep -Seconds 30
      
              Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
          }
      
          Disconnect-VIServer -Server * -Confirm:$false
      }
      
      $Functions = [scriptblock]::Create(@"
          Function CopyVMToHostIrving { $Function:CopyVMToHostIrving([string]$myVMHost) }
          Function CopyVMToHostPlano { $Function:CopyVMToHostPlano([string]$myVMHost) }
          Function CopyVMToHostAtlanta { $Function:CopyVMToHostAtlanta([string]$myVMHost) }
      "@)
      
      $TotalHostNum = (Get-ADComputer -Server ******************** -SearchBase "OU=********************" -Filter { Name -like "*CED-SQL-PC*" }).Count
      
      While ($Global:CompletedHosts.Count -lt $TotalHostNum) {
          Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
      
          Write-Host "Removing completed hosts from vCenter..."
          ForEach ($VMHost in (Get-VMHost -Location (Get-Datacenter "Profit Centers") | Where-Object { $_.Parent -ne "Upgrade Failures" })) {
              If (((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -ne $null -and $VMHost.Name -notin (Get-Job -State Running).Name.Trim("-TXINTATL")) -or (Get-VMHost $VMHost).ConnectionState -ne "Connected") {
                  Remove-VMHost $VMHost -Confirm:$false | Out-Null
                  If ($VMHost.Name -notin $Global:CompletedHosts) {
                      $Global:CompletedHosts = $Global:CompletedHosts + $VMHost.Name
                  }
              }
          }
      
          Write-Host "Adding additional hosts to vCenter..."
          If ($InputFile) {
              Add-VMHosts -MAXVMHostCount $MAXVMHostCount -InputFile $InputFile
          }
          Else {
              Add-VMHosts -MAXVMHostCount $MAXVMHostCount
          }
      
          $VMHosts = (Get-VMHost -Location (Get-Datacenter "Profit Centers") | Where-Object { $_.Parent -ne "Upgrade Failures" })
      
          Disconnect-VIServer -Server * -Confirm:$false
      
          ForEach ($VMHost in $VMHosts) {
              Write-Host "Checking if max job count has been reached..."
              While ((Get-Job -State Running).Count -ge ($IrvingMaxJobs + $PlanoMaxJobs + $AtlantaMaxJobs)) {
                  If (((Get-Date).hour -ge 6 -and (Get-Date).hour -lt 18) -and (Get-Date).DayOfWeek -ne "Saturday" -and (Get-Date).DayOfWeek -ne "Sunday") {
                      Write-Host "Total count of hosts that new VM was copied to: $Global:CompletedHosts.Count"
                      Exit
                  }
                  Else {
                      Start-Sleep -Seconds 60
                  }
              }
      
              Write-Host "Removing completed jobs..."
              ForEach ($Job in (Get-Job -State Completed)) {
                  If ($Job.Name.Trim("-TXINTATL") -notin $GlobalCompletedHosts) {
                      $Global:CompletedHosts = $Global:CompletedHosts + $Job.Name.Trim("-TXINTATL")
                  }
                  Remove-Job -Id $Job.Id
              }
      
              Write-Host "Starting jobs..."
              If ((Get-Job | Where { $_.Name.Trim("-TXINTATL") -eq $VMHost.Name }) -eq $null -and $VMHost.Name -notin $Global:CompletedHosts) {
                  If ((Get-Job | Where { $_.Name -like "*-TX" }).Count -lt $IrvingMaxJobs) {
                      Write-Host "Starting job for $VMHost using Irving Source" -ForegroundColor Yellow
                      Start-Job -InitializationScript $Functions -Script { CopyVMToHostIrving($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-TX") | Out-Null
                  }
                  ElseIf ((Get-Job | Where { $_.Name -like "*-INT" }).Count -lt $PlanoMaxJobs) {
                      Write-Host "Starting job for $VMHost using Plano Source" -ForegroundColor Yellow
                      Start-Job -InitializationScript $Functions -Script { CopyVMToHostPlano($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-INT") | Out-Null
                  }
                  ElseIf ((Get-Job | Where { $_.Name -like "*-ATL" }).Count -lt $AtlantaMaxJobs) {
                      Write-Host "Starting job for $VMHost using Atlanta Source" -ForegroundColor Yellow
                      Start-Job -InitializationScript $Functions -Script { CopyVMToHostAtlanta($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-ATL") | Out-Null
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-16
        • 1970-01-01
        • 1970-01-01
        • 2021-05-06
        • 1970-01-01
        • 2011-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多