Contributor
Contributor

Create multiple vm in parallel using powershell runspace

I have a problem with creating multiple VM's from template in single VIServer. In following code when I choose if I put anything bigger than 1 in throttle script only executes one vm and don't create any other, it seems to have problem with keeping the session most likely just reset it or modify it in $global:DefaultVIServer.

Code below is based on question in this thread: Thread does not create multiple VMs (session issue) The answer is to keep the same session all the time but I couldn't get this to work

I wonder if anyone had working solution in using runspace in powershell to create multiple vms in vmware ?

cls
Add-PSSnapin VMware.VimAutomation.Core | Out-Null
#import csv
$VMs
= Import-CSV 'filename.csv' -UseCulture
#connections array
$server
= @()
#threads
$throttle
= 2
# Create session state
$sessionState
= [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
# Create runspace pool consisting of runspaces
$RunspacePool
= [RunspaceFactory]::CreateRunspacePool(1, $throttle, $sessionState, $host)
$RunspacePool
.Open()
#array for jobs
$Jobs
= @()
#this contains all connected vSphere endpoints
$global
:DefaultVIServer

$User
= "domain\username"
$PWord
= ConvertTo-SecureString -String "password" -AsPlainText -Force
$Credential
= New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User, $PWord 



# SctiptBlock to execute for each job
$ScriptBlock
= {
  
Param ($VM, $ses)

  
Add-PSSnapin VMware.VimAutomation.Core | Out-Null
  
Write-Host $VM.Name "Father session: "  $ses.SessionSecret  

  
Connect-VIServer $VM.VIServer -Session $ses.SessionSecret -wa 0
  
Write-Host $VM.Name "Child session: "  $sessionf.SessionId

  
New-VM -Name $VM.Name -ResourcePool "..." -Location "Windows Servers" -Datastore "..." -DiskStorageFormat "..." -Notes "..." -Template "..."
}


# Starting script
Write-Host ("Starting script: {0}" -f (Get-Date))
$startTime
= Get-Date

$count
= 0
ForEach($VM in $VMs)
{

  $count 
= $count + 1

  
Write-Host "Current connections:"
  $Global
:DefaultVIServers.count

  $ses
= Connect-VIServer $VM.VIServer -Credential $Credential -wa 0  

  $Job
= [powershell]::create()
  $Job
.RunspacePool = $RunspacePool
  $Job
.AddScript($ScriptBlock).AddParameter("VM", $VM).AddParameter("ses", $ses)

  
Write-Host "Adding job to jobs list"  
  $Jobs
+= New-Object PSObject -Property @{
  
RunNum = $count
  
Job = $Job
  
Result = $Job.BeginInvoke() | Out-Null
  
}  
}

Write-Host "Waiting.." -NoNewline
Do {
  
Write-Host "." -NoNewline
  
Start-Sleep -Seconds 1
} While ( $Jobs.Result.IsCompleted -contains $false)

$endTime
= Get-Date
$totalSeconds
= "{0:N4}" -f ($endTime-$startTime).TotalSeconds
Write-Host "All jobs finished in $totalSeconds seconds"

Tags (2)
3 Replies
Contributor
Contributor

I am certainly not an expert, but I just finished doing something like this but used a powershell workflow using the parallel command

Maybe this will help? Dunno

Workflow Engine

{

    param(

        [string]$vc,

        [string]$ses

        )

$vcuser="root"

$vcpass="vcpass"

  foreach -parallel($name in $names)
  {
   InlineScript
    {
    
     #Add the SnapIn and Connect to the Management vCenter
     Add-PSSnapin VMWare.VimAutomation.Core          
     Connect-VIServer -Server $Using:vc -Session $Using:ses -User $Using:vcuser -Password $Using:vcpass

        #do something

    }#InlineScript

} #ForEach

} #Workflow

cls

Engine -vcenter "1.1.1.1" -session $global:DefaultVIServer.SessionSecret

Note: $names = "VM1","VM2","VM3"

Contributor
Contributor

Ran into the similar issue trying to run powershell inline script from RunDeck.

My script "rundeck-createvms.ps1" runs well in Windows interactive session but not from WinRM module used by RunDeck. So below is my wrapper for paraller vm creation.

$VCUser = "user"

$VCPass = "password"

$VCServer = "vcenter"

$vmNames = 'illya-test411','illya-test412','illya-test413' | Sort-Object

$myfolder = "IMAGETEST"

$mytemplate = "IMG-CENTOS704-VEN-201806092144"

$vmnetwork = "10.2.0.0/16"

$vmmemorygb = 7

$vmmcpu = 3

Get-Module -ListAvailable VMWare* | Import-Module | Out-Null

Write-Host "PowerCLI is loaded" -ForegroundColor Green

Connect-VIServer -Server $VCServer -User $VCUser -Password $VCPass -WarningAction SilentlyContinue | Out-Null

Write-Host "Connected to vCenter as $VCUser" -ForegroundColor Green

workflow vmcreate

{

param

    (

    [string]$vcenter,

    [string[]]$names,

    [string]$session,

    [string]$myfolder,

    [string]$mytemplate,

    [string]$vmnetwork,

    [int]$vmmemorygb,

    [int]$vmmcpu

    )

foreach -parallel($name in $names)

    {

    InlineScript

        {

        Connect-VIServer -Server $Using:vcenter -Session $Using:session | Out-Null

        & C:\Scripts\rundeck-createvms.ps1 -vmname $Using:name -myfolder $Using:myfolder -mytemplate $Using:mytemplate `

        -vmnetwork $Using:vmnetwork -vmmemorygb $Using:vmmemorygb -vmmcpu $Using:vmmcpu

        }

    }

}

vmcreate `

-vcenter $global:DefaultVIServer.Name `

-session $global:DefaultVIServer.SessionSecret `

-names  $vmNames `

-myfolder $myfolder `

-mytemplate $mytemplate `

-vmnetwork $vmnetwork `

-vmmemorygb $vmmemorygb `

-vmmcpu $vmmcpu

0 Kudos
Contributor
Contributor

>if anyone had working solution in using runspace in powershell to create multiple vms in vmware ?

powershell runspace or jobs won't work in this case due to vmware session handling - spent quite some time troubleshooting.

You have a long script and in each job, you connect to vcenter,  "first" jobs finished and automatically disconnect which kills connection in other jobs that are still running. Therefore out of multiple background jobs, the one that finished first will be successful. The solution is to connect to vcenter once in control script and use workflow for parallel processing.

0 Kudos