Private/Publish-VMs.ps1
function Confirm-ExistingVMRemovalAndAdd { Param ( [Parameter(Mandatory)] [VM]$VM, [HyperVServer]$HyperVServer, [string[]]$HyperVServers, [bool] $Replace, [bool] $Force, [DeploymentOptions] $DeploymentOptions ) $existingVM, $existingHypervisor = Assert-VMAlreadyExists -VM $VM -HyperVServers $HyperVServers if ($existingVM -and $Replace -and !$Force) { $name = $existingVM.Name Write-Host "$name already exists, replace?" -ForegroundColor Red $ReplaceConfirm = Read-Host "Press Y to confirm" if ($ReplaceConfirm.ToLower() -eq "y") { Remove-VM $VM.Name -ComputerName $existingHypervisor Add-VM -VM $VM -HyperVServer $HyperVServer -DeploymentOptions $DeploymentOptions } else { throw } } elseif ($existingVM -and $Replace -and $Force) { Write-Verbose "Existing VM found, replacing." Remove-VM $VM.Name -ComputerName $existingHypervisor Add-VM -VM $VM -HyperVServer $HyperVServer -DeploymentOptions $DeploymentOptions } elseif (!$existingVM) { Add-VM -VM $VM -HyperVServer $HyperVServer -DeploymentOptions $DeploymentOptions } } function Remove-ExistingVM { Param ( [Parameter(Mandatory)] [VM]$VM, [string[]]$HyperVServers, [bool] $Replace, [bool] $Force ) $existingVM, $existingHypervisor = Assert-VMAlreadyExists -VM $VM -HyperVServers $HyperVServers if ($existingVM -and $Replace -and !$Force) { $name = $existingVM.Name Write-Host "$name found, remove?" -ForegroundColor Red $ReplaceConfirm = Read-Host "Press Y to confirm" if ($ReplaceConfirm.ToLower() -eq "y") { Write-Verbose "Existing VM found, removing" Remove-VM $VM.Name -ComputerName $existingHypervisor } else { throw } } elseif ($existingVM -and $Replace -and $Force) { Write-Verbose "Existing VM found, removing" Remove-VM $VM.Name -ComputerName $existingHypervisor } } function Publish-VMs { Param ( [Parameter(Mandatory)] [VM[]]$VMs, [string[]]$HyperVServers, [DeploymentOptions]$DeploymentOptions, [bool] $Replace, [bool] $Force, [bool] $Destroy, [bool] $ReplaceUpFront ) [System.Collections.ArrayList]$VMList = $VMs if ($VMs.Where( { $_.Replicas -gt 0 }, 'First').Count -gt 0) { #Replicas Detected foreach ($replicasRequired in $VMs.Where{ $_.Replicas -gt 0 }) { $VMList.Remove($replicasRequired) $startReplicas = $replicasRequired.Replicas $replicaStartIndex = 1 if ($replicasRequired.ReplicaStartIndex -gt 0) { $replicaStartIndex = $replicasRequired.ReplicaStartIndex; $replicasRequired.Replicas = $replicasRequired.Replicas + $replicaStartIndex - 1 } foreach ($server in $replicasRequired.HyperVServers) { if ($server.MaxReplicas) { $crossServerMaxReplicas += $server.MaxReplicas } } if ($startReplicas -gt $crossServerMaxReplicas) { throw "Not enough Hypervisor capacity for VM's" } $hyperVIndex = 0; $guid = [guid]::NewGuid() For ($replicaStartIndex; $replicaStartIndex -le $replicasRequired.Replicas; $replicaStartIndex++) { $replica = $replicasRequired.Clone() $replica.Name = $replica.Name + $replicaStartIndex $replica.Replicas = 0 $replica.ReplicaGuid = $guid $orginalServers = $replica.HyperVServers $allocatedServer = $replica.HyperVServers[$hyperVIndex] $replica.HyperVServers = @() if ($allocatedServer.MaxReplicas) { #Do logic to calculate how many replicas already allocated to hypervisor, if assigning this one would breach then increment hypervindex do { $allocated = $false $allocatedServer = $orginalServers[$hyperVIndex] $reps = $VMList | Where-Object { $_.ReplicaGuid -eq $guid -and $_.HyperVServers[0].Name -eq $allocatedServer.Name } if ($reps.Count -eq $allocatedServer.MaxReplicas) { #Pick new server as allocated one at max if ($hyperVIndex + 1 -eq $orginalServers.Length) { $hyperVIndex = 0; } else { $hyperVIndex++; } } else { $replica.HyperVServers += $allocatedServer $allocated = $true } } While (!$allocated) } else { $replica.HyperVServers += $allocatedServer } if ($hyperVIndex + 1 -eq $orginalServers.Length) { $hyperVIndex = 0; } else { $hyperVIndex++; } $VMList.Add($replica) > $null } if ($replicasRequired.SkipNames.Length -gt 0) { Write-Verbose "Skips detected" foreach ($skip in $replicasRequired.SkipNames) { $vms = $VMList foreach ($vm in $vms) { if ($vm.Name -eq $skip) { $newVm = $vm $VMList.Remove($vm) $last = $VMList[-1] $iteration = ([int]($last.Name -replace '\D+(\d+)','$1')) +1 $newVm.Name = "Automation$iteration" $VMList.Add($newVm) } } } } } } write-output $VMList if (!$Destroy) { if ($ReplaceUpFront){ Write-Host "Removing existing VM's up front" foreach($vm in $VMList) { Remove-ExistingVM -VM $vm -HyperVServers $HyperVServers -Replace $Replace -Force $Force } } if ($DeploymentOptions.Parallel) { Get-Job | Remove-Job -Force $MaxThreads = 5 } $addBlock = { Param( [object] $VM, [object] $Provisioning, [object] $HyperVServer, [object] $HyperVServers, [object] $DeploymentOptions, [object] $Replace ) . .\Private\Publish-VMs.ps1 . .\Private\Add-VM.ps1 . .\Private\Assert-VMAlreadyExists.ps1 . .\Private\Classes.ps1 . .\Private\Initialize-VM.ps1 . .\Private\Remove-VM.ps1 $VM.Provisioning = $Provisioning Confirm-ExistingVMRemovalAndAdd -VM $VM -HyperVServers $HyperVServers -HyperVServer $vm.HyperVServers[0] -DeploymentOptions $DeploymentOptions -Replace $Replace -Force $true } Write-Host "Adding Virtual Machines" -ForegroundColor Yellow foreach ($vm in $VMList) { if ($DeploymentOptions.Parallel) { While ($(Get-Job -state running).count -ge $MaxThreads) { Start-Sleep -Milliseconds 3 } Start-Job -Scriptblock $addBlock -ArgumentList $vm, $vm.Provisioning, $key, $HyperVServers, $DeploymentOptions, $Replace } else { Confirm-ExistingVMRemovalAndAdd -VM $vm -HyperVServers $HyperVServers -HyperVServer $vm.HyperVServers[0] -DeploymentOptions $DeploymentOptions -Replace $Replace -Force $Force } } if ($DeploymentOptions.Parallel) { While ($(Get-Job -State Running).count -gt 0) { start-sleep 1 } #Get information from each job. foreach ($job in Get-Job) { $info = Receive-Job -Id ($job.Id) } #Remove all jobs created. Get-Job | Remove-Job } Write-Host "Virtual Machines Added" -ForegroundColor Green } else { Write-Host "Starting Destroy" -ForegroundColor Red if ($DeploymentOptions.Parallel) { Get-Job | Remove-Job -Force $MaxThreads = 5 } $destroyBlock = { Param( [object] $vm, [object] $HyperVServers, [object] $Force ) . .\Private\Publish-VMs.ps1 . .\Private\Add-VM.ps1 . .\Private\Assert-VMAlreadyExists.ps1 . .\Private\Classes.ps1 . .\Private\Initialize-VM.ps1 . .\Private\Remove-VM.ps1 $existingVM, $existingHypervisor = Assert-VMAlreadyExists -VM $vm -HyperVServers $HyperVServers if ($existingVM) { Remove-VM $vm.Name -ComputerName $existingHypervisor } } foreach ($vm in $VMList) { if ($DeploymentOptions.Parallel) { While ($(Get-Job -state running).count -ge $MaxThreads) { Start-Sleep -Milliseconds 3 } Start-Job -Scriptblock $destroyBlock -ArgumentList $vm, $HyperVServers, $Force } else { $existingVM, $existingHypervisor = Assert-VMAlreadyExists -VM $vm -HyperVServers $HyperVServers if ($existingVM -and !$Force) { $name = $existingVM.Name Write-Host "Remove $name ?" -ForegroundColor Red $RemoveConfirm = Read-Host "Press Y to confirm" if ($RemoveConfirm.ToLower() -eq "y") { Remove-VM $vm.Name -ComputerName $existingHypervisor } else { throw } } elseif ($existingVM -and $Force) { Remove-VM $vm.Name -ComputerName $existingHypervisor } } } if ($DeploymentOptions.Parallel) { While ($(Get-Job -State Running).count -gt 0) { start-sleep 1 } #Get information from each job. foreach ($job in Get-Job) { $info = Receive-Job -Id ($job.Id) } #Remove all jobs created. Get-Job | Remove-Job } Write-Host "Destroy Complete" -ForegroundColor Red } } |