Skip to content

Instantly share code, notes, and snippets.

@alainassaf
Last active December 15, 2023 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alainassaf/0e73ce6e55412b7268edbe552a58f883 to your computer and use it in GitHub Desktop.
Save alainassaf/0e73ce6e55412b7268edbe552a58f883 to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Reviews and evenly distributes VDA's within a Citrix Hypervisor pool.
.DESCRIPTION
Reviews and evenly distributes VDA's within a Citrix Hypervisor pool.
.PARAMETER XenServer_poolmaster
Mandatory string parameter. IP of the Citrix Hypervisor pool master to optimize.
.PARAMETER XenServer_networkname
Mandatory string parameter. Network name of the Citrix Hpervisor pool's management network
.PARAMETER XenServer_SRName
Mandatory string parameter. Storage Repository name that stores the vDisks of the Citrix Hpervisor pool
.EXAMPLE
optimize-hypervisorvdas.ps1 -xenserver_poolmaster "127.0.0.1" -xenserver_networkname "HypervisorMGMTNet" -XenServer_SRName "HypervisorSR" -verbose
Counts the total VMs in the 127.0.0.1 Hypervisor pool and evently distributes them with additional console feedback.
.INPUTS
None
.OUTPUTS
None
.NOTES
NAME: optimize-hypervisorvdas.ps1
VERSION: 1.0.2
CHANGE LOG - Version - When - What - Who
0.0.1 - 12/06/2022 - Initial script - Alain Assaf
0.0.2 - 12/22/2022 - Added hypervisor connection/disconnection functions - Alain Assaf
0.0.3 - 12/28/2022 - Added new functions get-hypNetwork & get-hypSR - Alain Assaf
0.0.4 - 12/28/2022 - Added params XenServer_networkname & XenServer_SRName - Alain Assaf
0.0.5 - 12/29/2022 - Added change to get-ctxHypVMTable function - Alain Assaf
0.0.6 - 12/30/2022 - Added additional functions related to migration - Alain Assaf
0.0.7 - 2/14/2023 - Added new link. Updates function calls for new params - Alain Assaf
0.0.8 - 2/23/2023 - Make sure all existing XenServer connected are stopped before script starts - Alain Assaf
1.0.0 - 3/06/2023 - Removed commented lines and converted write-host to write-verbose - Alain Assaf
1.0.1 - 3/06/2023 - Updated Requries statement - Alain Assaf
1.0.2 - 3/07/2023 - Updated help - Alain Assaf
AUTHOR: Alain Assaf
LASTEDIT: March 07, 2023
.LINK
https://jordantheitguy.com/2019/06/24/how-to-powershell-progress-bars/
https://discussions.citrix.com/topic/415099-invoke-xenvm-xenaction-migratesend/page/2/
https://discussions.citrix.com/topic/399153-vm-migration-to-homeserver-via-powershell/
https://devblogs.microsoft.com/scripting/rounding-numberspowershell-style/
http: //www.linkedin.com/in/alainassaf/
#>
[CmdletBinding()]
Param(
[parameter(Mandatory)]
[string]$XenServer_poolmaster,
[parameter(Mandatory)]
[string]$XenServer_networkname,
[parameter(Mandatory)]
[string]$XenServer_SRName
)
#region functions
function get-scriptCredential {
param (
[Parameter(Mandatory = $true)]
[String]$userName,
[Parameter(Mandatory = $true)]
[String]$PassPath
)
# If Password file does not exist, create it
if ((Test-Path -Path $PassPath) -eq $False) {
(Get-Credential -Message "ENTER CREDENTIALS" -UserName $userName).Password | ConvertFrom-SecureString | Out-File $PassPath
}
$cred_password = Get-Content $PassPath | ConvertTo-SecureString
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userName, $cred_password
Return $credential
}
Function Get-MySnapin {
<#
.SYNOPSIS
Checks for a PowerShell Snapin(s) and imports it if available, otherwise it will display a warning and exit.
.DESCRIPTION
Checks for a PowerShell Snapin(s) and imports it if available, otherwise it will display a warning and exit.
.PARAMETER snapins
Required parameter. List of PSSnapins separated by commas.
.INPUTS
None
.OUTPUTS
None
.EXAMPLE
PS> get-MySnapin PSSNAPIN
Checks system for installed PSSNAPIN and imports it if available.
.LINK
http://www.linkedin.com/in/alainassaf/
https://github.com/alainassaf/get-mysnapin
.NOTES
NAME : Get-MySnapin
VERSION : 1.01
CHANGE LOG - Version - When - What - Who
1.00 - 02/13/2017 - Initial script - Alain Assaf
1.01 - 11/7/2017 - Added try/catch - Alain Assaf
LAST UPDATED: 11/7/2017
AUTHOR : Alain Assaf
#>
Param([string]$snapins)
$ErrorActionPreference = 'silentlycontinue'
foreach ($snap in $snapins.Split(",")) {
if (-not(Get-PSSnapin -Name $snap)) {
if (Get-PSSnapin -Registered | Where-Object { $_.name -like $snap }) {
try {
Add-PSSnapin -Name $snap
$true
} catch {
Write-Warning "$snap PowerShell Cmdlet not available."
Write-Warning "Please run this script from a system with the $snap PowerShell Cmdlet installed."
exit 1
}
}
}
}
}
function connect-ctxhyp {
<#
.SYNOPSIS
Connects to Citrix Hypervisor. Returns object with XenServer Connection
.PARAMETER poolMaster
Required string parameter. IP of the Hypervisor poolmaster.
.PARAMETER hypCreds
Required PSCredential parameter. Username and password PSCredentail object to authenticate to the Hypervisor.
.INPUTS
None
.OUTPUTS
XenAPI.Session
.EXAMPLE
PS> connect-ctxhyp -poolMaster "192.168.25.1" -hypCreds $credentials
Connects Citrix Hypervisor at 192.168.25.1 using $credentials for authentication.
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : connect-ctxhyp
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/22/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/22/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
param (
[Parameter(Mandatory)]
[string]$poolMaster,
[Parameter(Mandatory)]
[System.Management.Automation.PSCredential]$hypCreds
)
Try {
Connect-XenServer -Server $poolMaster -Creds $hypCreds -NoWarnNewCertificates -SetDefaultSession
$hypSession = Get-XenSession
return $hypSession
} Catch [XenAPI.Failure] {
Write-Warning "Failed to connect to [$poolMaster]"
Exit 1
}
}
function disconnect-ctxhyp {
<#
.SYNOPSIS
Disconnect all open Citrix Hypervisor sessions.
.INPUTS
None
.OUTPUTS
None
.EXAMPLE
PS> disconnect-ctxhyp
Disconnects and closes all open Citrix Hyperivsor sessions
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : disconnect-ctxhyp
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/22/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/22/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
param ()
try {
Get-XenSession | Disconnect-XenServer | Out-Null
} catch {
Write-Warning "Already disconnected from XenServer"
}
}
function get-ctxHypVMTable {
<#
.SYNOPSIS
Generates a table with the hypervisor host, uuid, and VM Count.
.INPUTS
XenAPI.Session
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> get-ctxHypVMTable
Generates a table with the hypervisor host, uuid, and VM Count for the current Citrix hypervisor session
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-ctxHypVMTable
VERSION : 1.0.2
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/22/2022 - Initial script - Alain Assaf
1.0.1 - 12/29/2022 - Added write-progress to show progress - Alain Assaf
1.0.2 - 2/14/2023 - Added Session param - Alain Assaf
LAST UPDATED: 12/29/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter()]
[XenAPI.Session]$hypSession
)
$hypTable = @()
[int]$hypCount = 1
$hypHosts = Get-XenHost -SessionOpaqueRef $hypSession.opaque_ref | Sort-Object name_label
foreach ($hypervisor in $hypHosts) {
Write-Progress -Activity "Creating VM Table" -Status "Examing Host - $($hypervisor.Name_label) $hypCount of $($hypHosts.Count)"
$row1 = $hypervisor.name_label
$row2 = $hypervisor.uuid
$row3 = ($hypervisor | Select-Object -ExpandProperty resident_VMs | ForEach-Object { (Get-XenVM -opaque_ref $_) | Where-Object { $_.is_control_domain -eq $false } }).count
$hypTable += [PSCustomObject]@{HypervisorName = $row1; UUID = $row2; VMCount = $row3 }
$hypCount++
}
return $hypTable
}
function get-ctxHypSource {
<#
.SYNOPSIS
Returns a table of hypervisor hosts with more than the 'ideal' number of VMs.
.INPUTS
PSCustomObject
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> get-ctxHypSource -idealNumberOfVMs 8 -hypTable $HyperVisorTable
Returns a subset of items from $HypervisorTable with a VM count higher than 8
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-ctxHypSource
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/29/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/29/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[Int]$idealNumberOfVMs,
[Parameter(Mandatory)]
[PSCustomObject]$hypTable
)
$hypSourceTable = @()
[int]$hypCount = 1
foreach ($hypervisor in $hypTable) {
Write-Progress -Activity "Creating Hypervisor Source Table" -Status "Examing Host - $($hypervisor.Name_label) $hypCount of $($hypTable.Count)"
if ($hypervisor.VMCount -gt $idealNumberOfVMs) {
$row1 = $hypervisor.HypervisorName
$row2 = $hypervisor.uuid
$row3 = $hypervisor.VMcount
$hypSourceTable += [PSCustomObject]@{HypervisorName = $row1; UUID = $row2; VMCount = $row3 }
$hypCount++
}
}
return $hypSourceTable
}
function get-ctxHypDest {
<#
.SYNOPSIS
Returns a table of hypervisor hosts with less than the 'ideal' number of VMs.
.INPUTS
PSCustomObject
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> get-ctxHypDest -idealNumberOfVMs 8 -hypTable $HyperVisorTable
Returns a subset of items from $HypervisorTable with a VM count less than 8
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-ctxHypDest
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/29/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/29/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[Int]$idealNumberOfVMs,
[Parameter(Mandatory)]
[PSCustomObject]$hypTable
)
$hypDestTable = @()
[int]$hypCount = 1
foreach ($hypervisor in $hypTable) {
Write-Progress -Activity "Creating Hypervisor Destination Table" -Status "Examing Host - $($hypervisor.Name_label) $hypCount of $($hypTable.Count)"
if ($hypervisor.VMCount -lt $idealNumberOfVMs) {
$row1 = $hypervisor.HypervisorName
$row2 = $hypervisor.uuid
$row3 = $hypervisor.VMcount
$hypDestTable += [PSCustomObject]@{HypervisorName = $row1; UUID = $row2; VMCount = $row3 }
$hypCount++
}
}
return $hypDestTable
}
function get-hypHost {
<#
.SYNOPSIS
Returns a hypervisor host object
.INPUTS
None
.OUTPUTS
XenAPI.Host
.EXAMPLE
PS> get-hypHost -hostUUID "b671f78b-db28-4902-ad07-062c368fd8c2"
Retrurns XenAPI.Host object with uuid b671f78b-db28-4902-ad07-062c368fd8c2
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-hypHost
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/23/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/23/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
$hostUUID
)
try {
$hypHost = Get-XenHost -Uuid $hostUUID
Return $hypHost
} catch {
Write-Warning "Could not find Hypervisor with uuid: [$hostUUID]"
Exit 1
}
}
function get-hypNetwork {
<#
.SYNOPSIS
Returns a hypervisor network
.INPUTS
None
.OUTPUTS
XenAPI.Network
.EXAMPLE
PS> get-hypNetwork -xenNetName "PRODUCTION"
Retrurns XenAPI.Network object with name_label'"PRODUCTION'
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-hypNetwork
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/28/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/28/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[String]$xenNetName
)
try {
$hypNetwork = Get-XenNetwork -name_label $xenNetName
Return $hypNetwork
} catch {
Write-Warning "Could not find Hypervisor network named: [$xenNetName]"
Write-Warning "Closing Citrix Hypervisor connection"
disconnect-ctxhyp
Exit 1
}
}
function get-hypSR {
<#
.SYNOPSIS
Returns a hypervisor Storage Repository
.INPUTS
None
.OUTPUTS
XenAPI.Storage
.EXAMPLE
PS> get-hypSR xenSRName "VDA-SR"
Retrurns XenAPI.Storage object with name_label 'VDA-SR'
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-hypSR
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 12/28/2022 - Initial script - Alain Assaf
LAST UPDATED: 12/28/2022
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[String]$xenSRName
)
try {
$hypSR = Get-XenSR -name_label $xenSRName
Return $hypSR
} catch {
Write-Warning "Could not find Hypervisor Storage Repository named: [$xenSRName]"
Write-Warning "Closing Citrix Hypervisor connection"
disconnect-ctxhyp
Exit 1
}
}
function get-vmToMigrate {
<#
.SYNOPSIS
Returns the first VM object from a hypervisor with its disks. This VM will be migrated off the hypervisor host.
.PARAMETER hypTableRow
Mandatory PSCustomObject of a hypTable row
.PARAMETER vmSR
Mandatory Storage Repository where migration VM disks reside
.INPUTS
PSCustomObject
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> get-vmToMigrateName -hypTableRow $HypTableRow -vmSR $vmSR
Queries hypervisor for VMs and returns first 1 to migrate with the VM's disks
.LINK
http://www.linkedin.com/in/alainassaf/
.NOTES
NAME : get-vmToMigrateName
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 1/26/2023 - Initial script - Alain Assaf
LAST UPDATED: 1/26/2023
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[PSCustomObject]$hypTableRow,
[Parameter(Mandatory)]
$vmSR
)
$migrateHostVM = (Get-XenHost -Uuid $hypTableRow.uuid) | Select-Object -ExpandProperty resident_VMs | Select-Object -First 1
$VMtoMove = Get-XenVM -opaque_ref $migrateHostVM
##VDI's should be resolved from $tmpVM.VBDs https://discussions.citrix.com/topic/415099-invoke-xenvm-xenaction-migratesend/page/2/
$vdirefs = @()
foreach ($itemvbd in $VMtoMove.VBDs) {
$vbdvm = Get-XenVBD -opaque_ref $itemvbd.opaque_ref
if ($vbdvm.type -eq "Disk") {
$vdirefs += Get-XenVDI -opaque_ref $vbdvm.VDI.opaque_ref | ConvertTo-XenRef
}
}
#Map disks to $vdimap to use in migrate tasks
$vdimap = @{}
foreach ($vdiref in $vdirefs) {
$vdimap.Add([XenAPI.XenRef[XenAPI.VDI]]$vdiref, [XenAPI.XenRef[XenAPI.SR]]$vmSR);
}
$migrateVM = [PSCustomObject]@{vmToMigrate = $VMtoMove; vdiMap = $vdimap }
Return $migrateVM
}
function get-destHyp {
<#
.SYNOPSIS
Gets destination host to migrate a VM to
.PARAMETER hypTableRow
Mandatory PSCustomObject of a hypTable row
.PARAMETER hypNet
Mandatory [XenAPI.Network] that VM resides on
.INPUTS
PSCustomObject,XenAPI.Network
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> get-destHyp -hypTableRow $HypTableRow -hypNet $HypervisorNetwork
Returns a XenAPI.VM of the destination hypervisor
.LINK
http://www.linkedin.com/in/alainassaf/
https://discussions.citrix.com/topic/415099-invoke-xenvm-xenaction-migratesend/page/2/
.NOTES
NAME : get-destHyp
VERSION : 1.0.0
CHANGE LOG - Version - When - What - Who
1.0.0 - 1/27/2023 - Initial script - Alain Assaf
LAST UPDATED: 1/27/2023
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[PSCustomObject]$hypTableRow,
[Parameter(Mandatory)]
[XenAPI.Network]$hypNet
)
$desthost = Get-hypHost -hostUUID $hypTableRow.uuid
$VMdest = Invoke-XenHost -XenHost $desthost -XenAction migratereceive -network $hypNet -PassThru
return $VMdest
}
function invoke-vmMigration {
<#
.SYNOPSIS
Initates VM Migration
.PARAMETER VMtoMigrate
Mandatory XenAPI.VM parameter of VM to migrate
.PARAMETER DestinationHost
Mandatory object of the destination Hypervisor
.PARAMETER VMVIFMap
Mandatory object array of Migration VM's vifs
.PARAMETER VMVDIMap
Mandatory object array of Migration VM's disks
.PARAMETER hpySession
Mandatory XenAPI.Session object of the XenServer session where the migration will occur
.INPUTS
PSCustomObject,XenAPI.Network
.OUTPUTS
PSCustomObject
.EXAMPLE
PS> invoke-vmMigration -hypTableRow $HypTableRow -hypNet $HypervisorNetwork
Starts migratio of
.LINK
http://www.linkedin.com/in/alainassaf/
https://discussions.citrix.com/topic/415099-invoke-xenvm-xenaction-migratesend/page/2/
.NOTES
NAME : get-destHyp
VERSION : 1.0.2
CHANGE LOG - Version - When - What - Who
1.0.0 - 1/27/2023 - Initial script - Alain Assaf
1.0.1 - 1/30/2023 - Added additional parameters - Alain Assaf
1.0.2 - 2/14/2023 - Added VMVIFMap param - Alain Assaf
LAST UPDATED: 2/14/2023
AUTHOR : Alain Assaf
#>
#Requires -Version 4
#Requires -Module XenServerPSModule
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[XenAPI.VM]$VMtoMigrate,
[Parameter(Mandatory)]
$DestinationHost,
[Parameter(Mandatory)]
[AllowNull()]
$VMVIFMap,
[Parameter(Mandatory)]
$VMVDIMap,
[Parameter(Mandatory)]
[XenAPI.Session]$hpySession
)
$xenMotionTask = Invoke-XenVM $VMtoMigrate -XenAction migratesend -live $true -dest $DestinationHost -VifMap $VMVIFMap -VdiMap $VMVDIMap -SessionOpaqueRef $hypSession.opaque_ref -BestEffort -Async -PassThru
return $xenMotionTask
}
#endregion
#region variables
$datetime = Get-Date -Format "MM-dd-yyyy_HH-mm"
$Domain = (Get-ChildItem env:USERDNSDOMAIN).value
$ScriptRunner = (Get-ChildItem env:username).value
$compname = (Get-ChildItem env:COMPUTERNAME).value
$scriptName = $MyInvocation.MyCommand.Name
$scriptpath = $MyInvocation.MyCommand.Path
#$currentDir = Split-Path $MyInvocation.MyCommand.Path
#endregion
#region modules
# Import the Citrix Broker PowerShell module
Get-MySnapin Citrix.Broker.Admin.V2
# Import the XenServer Module
Get-MySnapin XenServerPowerShell
#endregion
#Remove any existing XenServer sessions
disconnect-ctxhyp
#Get XenServer Credential
Write-Verbose "Getting XenServer Credentials (for root user)..."
$XenServer_credential = get-scriptCredential -userName "root" -passpath "c:\temp\XenServer_pool.pwd"
#Connect to XenServer
$session = connect-ctxhyp -poolMaster "$XenServer_poolmaster" -hypCreds $XenServer_credential
#Get Pool Friendly name. Populate to match your environment
switch ($XenServer_poolmaster) {
"127.0.0.1" { $xsn = "XS-Pool1"; break }
"127.0.0.10" { $xsn = "XS-Pool2"; break }
"127.0.0.20" { $xsn = "XS-Pool3"; break }
"127.0.0.30" { $xsn = "XS-Pool4"; break }
default { "UNKNOWN XENSERVER"; break }
}
#This network will be used for VM migration
$xennet = get-hypNetwork -xenNetName $XenServer_networkname
if ($null -eq $xennet) {
Write-Warning "XenServer network [$XenServer_networkname] was not correct. Try another network name."
disconnect-ctxhyp
Write-Warning "Exiting script"
exit 1
}
# Get Storage Repository to migrate VM to (usually the same if in the same pool)
$sr2ref = get-hypSR -xenSRName $XenServer_SRName | ConvertTo-XenRef
if ($null -eq $sr2ref) {
Write-Warning "XenServer Storage Repository [$XenServer_SRName] was not correct. Try another SR name."
disconnect-ctxhyp
Write-Warning "Exiting script"
exit 1
}
#region main
$hostsToBalance = get-ctxHypVMTable -hypSession $session
$totalHosts = $hostsToBalance.count
$vms = Get-XenVM | Where-Object { $_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false }
$vdas = $vms | Where-Object { $_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false } | Select-Object name_label | Sort-Object name_label
$totalVms = $vdas.count
$optimalVMCount = [math]::Round($totalVms / $totalHosts)
Write-Host "Optimizing XS Pool: [$xsn]"
Write-Host "Number of hosts: [$totalHosts]"
Write-Host "Number of virtual machines: [$totalVms]"
Write-Host "Optimal VMs to Host count: [$optimalVMCount]"
# Get set of hypervisors with fewer and more than $optimalVMCount
$DestinationHypervisors = get-ctxHypDest -idealNumberOfVMs $optimalVMCount -hypTable $hostsToBalance
$SourceHypervisors = get-ctxHypSource -idealNumberOfVMs $optimalVMCount -hypTable $hostsToBalance
# Balance VMs
foreach ($srchyp in $SourceHypervisors) {
while ($srchyp.VMCount -gt $optimalVMCount) {
foreach ($desthyp in $DestinationHypervisors) {
if ($desthyp.VMCount -lt $optimalVMCount) {
$srcVM = get-vmToMigrate -hypTableRow $srchyp -vmSR $sr2ref
[string]$tmpName = $srcvm.vmToMigrate.name_label
$destHypHost = get-destHyp -hypTableRow $desthyp -hypNet $xennet
Write-Verbose "Migrating [$tmpName]"
$migrateTask = invoke-vmMigration -VMtoMigrate $srcVM.vmToMigrate -DestinationHost $destHypHost -VMVIFMap $vifmap -VMVDIMap $srcVM.vdiMap -hpySession $session
Wait-XenTask -Task $migrateTask -ShowProgress
$desthyp.VMCount++
$srchyp.VMCount--
Write-Verbose "---------------------------------------"
Write-Verbose "Source Host"
$srchyp | Select-Object -Property *
Write-Verbose "Destination Host"
$desthyp | Select-Object -Property *
Write-Verbose "---------------------------------------"
break
}
}
}
}
#endregion
#Disconnect from XenServer
disconnect-ctxhyp
#End script info
Write-Verbose "SCRIPT NAME: $scriptName"
Write-Verbose "SCRIPT PATH: $scriptPath"
Write-Verbose "SCRIPT RUNTIME: $datetime"
Write-Verbose "SCRIPT USER: $ScriptRunner"
Write-Verbose "SCRIPT SYSTEM: $compname.$domain"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment