[Powershell] vCPU to Physical Core for XenApp VM

For our Citrix XenApp environment that runs on ESXi, we tend to keep a 1:1 ratio when it comes to physical cores and vCPUs. In other words, an ESXi host with 12 cores, will only be running 6 XenApp VMs with 2 cores or 3 XenApp VMs with 4 cores or any other combination, just as long as the vCPUs configured on the VM, never exceed the number of physical cores present in the host.

What about Hyperthreading? The extra HyperThreads that a physical CPU offers are not used in the core to vCPU ratio because specifically in a Citrix XenApp workload, they don’t offer a guaranteed performance boost. HyperThreading will be enabled in the BIOS though because it doesn’t hurt the performance.

This post by Frank Denneman explains how ESXi treats physical CPUs, cores and HyperThreads much better than I could. Be sure to read it.

When administering a vSphere environment with multiple admins, it sometimes happens and ESXi is put into maintenance mode, VMs are moved and when the ESXi is available again we see that our 1 vCPU to 1 core rule is not kept. Therefore we’re using this simple PowerShell script to quickly see if all VMs have their 1 to 1 ratio delivered.

I’m no PowerShell whizz and I bet Alan or Luc can do this in a one liner, but here it is:

$user = Get-Credential

$vCenters = @()

$vCenters = "vCenter01", "vCenter02"

$Report = @()

Foreach( $vCenter in $vCenters )


Connect-VIServer -Server $vCenter -Credential $user


# Only read Clusters that have "CTX" in their name

$ClusterList = Get-Cluster | Where { $_.Name -match "CTX" }

ForEach( $Cluster in $ClusterList )


$hostlist = Get-Cluster -Name $Cluster.Name | Get-VMHost | Sort-Object Name

ForEach( $ESXi in $hostlist )


$HostCores = $ESXi.NumCpu

$VMList = Get-VMHost -Name $ESXi.Name | Get-VM | Where { $_.PowerState -eq "PoweredOn" }

$VMCores = 0

$row = "" | Select ClusterName, HostName, HostCores, VMTotalvCPU

ForEach( $vm in $VMList )


$VMCores += $vm.NumCpu


$row.ClusterName = $Cluster.Name

$row.HostName = $ESXi.Name

$row.HostCores = $ESXi.NumCpu

$row.VMTotalvCPU = $VMCores

$Report += $row


# Output per host

Write-Host $row.ClusterName " ESXi host " $ESXi.Name " has " $HostCores " physical cores and a total of " $VMCores " vCPU assigned."



Disconnect-VIServer -Server $vCenter -Confirm:$false


$Report | Export-Csv "e:\csv-scripts\Citrix-core-to-vcpu.csv"

Enjoy the script.