If you have PSRemoting enabled on the target servers, the simplest approach would be to use Invoke-Command. When you pass it an array to the ComputerName parameter, it automatically does the operation in parallel (up to a maximum number at a time, which you can specify with the -ThrottleLimit parameter). For example:
Function Pick-VMHost { $Servers = @('host00', 'host01', 'host02', 'host03') $UseHost = @{} $VMRAM = 1.5GB $VMDiskSize = 40GB $serverMetrics = Invoke-Command -ComputerName $Servers -ScriptBlock { $CPU = (Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -MaxSamples 5).CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average $RAM = (Get-Counter -Counter "\Memory\Available Bytes" -SampleInterval 1 -MaxSamples 5).CounterSamples.CookedValue | Measure-Object -Average | Select-Object -ExpandProperty Average $Disk = Get-WmiObject win32_logicaldisk -Filter "DeviceID='D:'" | Select-Object -ExpandProperty FreeSpace New-Object psobject -Property @{ CPU = $CPU RAM = $RAM Disk = $Disk } } # Code here locally to determine which host to use from the $serverMetrics array. Each object will have a PSComputerName property automatically added by PSRemoting. $UseHost.PSComputerName } $Result = Pick-VMHost