I’ve written a script to query multiple Hyper-V hosts for some metrics, then using some logic, returns the name of host, that I can then use to create a vm on. Here is my script, note being I haven’t parameterized it yet.
I feel like this code isn’t well written and there is a better way to do this, I’ve tried use just Get-Counter on its own but didn’t find a way to get average results for the counters, tried using Jobs, but couldn’t figure out how to return values properly, I’ve ended up using a Workflow. I’ve also posted part of this script on StackOverflow, because I couldn’t at the time figure out how to return the values I wanted in a meaningful way.
Finally I know that Hyper-V has VM Metric functionality, but as far as I’m aware it only queries the VM’s and not the host.
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
This code still collects each counter synchronously on the remote computers, but process the computers themselves in parallel. If you need to parallelize the counter collection as well, that’s probably also possible, but would involve a lot more code, and may not be worth the effort (depends on how long this takes to run, and if it meets your needs already.)
I didn’t know about New-Object, more reading to do. If I want to run the commands synchronously on each remote machine, would you recommend using a workflow? As it is at the moment, I will keep the code as is, but if I add more counters then I might need to speed up the process.