= Hyper-V Disks Load and Performance =
**Summary**: How to measure Hyper-V 2 disk load and performance. \\
**Date**: Around 2020 \\
**Refactor**: 1 March 2025: Checked links and formatting. \\
{{tag>hyperv powershell}}
For a project I need how much bandwidth was required considering hoe much data was written to disk (All VMs were to be replicated to a different location). As I soon find out is that hyper-V does not keep this kind of data stored somewhere as vCenter does in a vSphere environment. Since Hyper-V 2 there are a few commands available to see the disk load end measure this. However, I found that the commands are unreliable, and especially in a Virtual Machine Manager environment where you run into name collision problems between VMM and Hyper-V commandlets (note that you sometimes can prefix commands like Hyper-V\get-VM).
== The script ==
# Script Variables
$scriptname = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString())
$scriptlocation = Split-Path $myinvocation.mycommand.path
# Start transcript for full logging capabilities
start-transcript -path "$scriptlocation\logtranscript.txt"
# Mail settings
#$weekdate = Get-Date -uformat %V
#$weekdate = get-date -Format yyyyMMdd-HHmm
$mailserver = "smtpserver"
$toemail = "sjoerd_getshifting.com"
$ccmail = "sjoerd_getshifting.com"
$fromemail = "$scriptname_getshifting.com"
#$monthreport = "$scriptlocation\$weekdate-$scriptname.csv"
# Run this script from a server with Virtual Machine Manager installed as well as the RSAT tools
$vmmserver = "vmm.getshifting.local"
Get-SCVMMServer $vmmserver
# Because the VMM server has both Hyper-V and VMM commandlets installed, and these commandlets can have the same name (or an alias), use all Hyper-V commands as 'Hyper-V\commandlet'
## For example: Hyper-V\Get-VM
Function Send-Email ($subject, $info){
# Send high prio email without attachment
if ($priority -eq "high" -and $monthreport -eq $null){
Send-MailMessage -To $toemail -From $fromemail -cc $ccmail -SmtpServer $mailserver -Subject $subject -Body $info -BodyAsHtml -Priority High
}
# Send mail without attachment (some Controls do not need attachments)
elseif ($monthreport -eq $null){
Send-MailMessage -To $toemail -From $fromemail -cc $ccmail -SmtpServer $mailserver -Subject $subject -Body $info -BodyAsHtml
}
else{
Send-MailMessage -To $toemail -From $fromemail -cc $ccmail -SmtpServer $mailserver -Subject $subject -Body $info -BodyAsHtml -Attachments "$monthreport"
}
}
Function Show-Menu{
param (
[string]$Title = 'Hyper-V Performance'
)
#Clear-Host
Write-Host "================ $Title ================"
Write-Host "1: Press '1' to enable and reset resourcemonitoring in cluster1 (PRD)"
Write-Host "2: Press '2' to collect disk resourcemonitoring in cluster1 (PRD)"
Write-Host "3: Press '3' to enable and reset resourcemonitoring in cluster2 (Test)"
Write-Host "4: Press '4' to collect disk resourcemonitoring in cluster2 (Test)"
Write-Host " "
Write-Host "5: Press '5' to disable resourcemonitoring in cluster1 and cluster2"
Write-Host " "
Write-Host "The report will be send to $toemail "
Write-Host "Q: Press 'Q' to quit."
}
Function Enable-Metering{
foreach($node in $nodes) {
Write-host "Node: $node"
#Set-VMHost -ComputerName $node -ResourceMeteringSaveInterval 24:00:00
Set-VMHost -ComputerName $node -ResourceMeteringSaveInterval 5:00:00
Get-VMHost -ComputerName $node | select ResourceMeteringSaveInterval
$vms = Hyper-V\Get-VM -ComputerName $node
foreach ($vm in $vms){
$name = $vm.name
write-host "VMname: $name"
$vm | Enable-VMResourceMetering
$vm | Reset-VMResourceMetering
}
}
}
Function Disable-Metering{
foreach($node in $nodes) {
Write-host "Node: $node"
$vms = Hyper-V\Get-VM -ComputerName $node
foreach ($vm in $vms){
$name = $vm.name
write-host "VMname: $name"
$vm | Disable-VMResourceMetering
}
}
}
Function Collect-Metering{
$allvms = @()
foreach($node in $nodes) {
Write-host "Node: $node"
$vms = Hyper-V\Get-VM -ComputerName $node
$measures = Hyper-V\Get-VM -ComputerName $node | Measure-VM | select vmname,meteringduration,AggregatedAverageNormalizedIOPS,AggregatedDiskDataRead,AggregatedDiskDataWritten,AggregatedNormalizedIOCount
foreach ($vm in $vms){
$vminfo = "" | select Name,State,MonitoringEnabled,MeteringDuration,AggregatedAverageNormalizedIOPS,AggregatedDiskDataRead,AggregatedDiskDataWritten,AggregatedNormalizedIOCount
#write-host "VM: $vm"
#$vmobject = Hyper-V\Get-VM -ComputerName $node | where {$_.Name -like "*$vm*"}
#write-host "VMobject: $vmobject"
$name = $vm.name
write-host "VMname: $name"
$vminfo.name = $name
$vminfo.state = $vm.state
$vminfo.monitoringenabled = $vm.ResourceMeteringEnabled
$measure = $measures | where {$_.vmname -eq $name}
#foreach ($measure in $measures)
$vminfo.meteringduration = $measure.meteringduration
$vminfo.AggregatedAverageNormalizedIOPS = $measure.AggregatedAverageNormalizedIOPS
$vminfo.AggregatedDiskDataRead = $measure.AggregatedDiskDataRead
$vminfo.AggregatedDiskDataWritten = $measure.AggregatedDiskDataWritten
$vminfo.AggregatedNormalizedIOCount = $measure.AggregatedNormalizedIOCount
$allvms += $vminfo
}
}
$allvms | export-csv -NoTypeInformation $monthreport
$subject = $Cluster + " Hyper-V Performance Report"
$body = "See the attached report"
Send-Email $subject $body
}
# Start menu
do
{
Show-Menu
$selection = Read-Host "Please make a selection"
switch ($selection)
{
'1' {
$cluster = "cluster1.prd.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
Enable-Metering
} '2' {
$cluster = "cluster1.prd.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
$weekdate = get-date -Format yyyyMMdd-HHmm
$monthreport = "$scriptlocation\$weekdate-$scriptname.csv"
Collect-Metering
} '3' {
$cluster = "cluster2.test.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
Enable-Metering
} '4' {
$cluster = "ccluster2.test.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
$weekdate = get-date -Format yyyyMMdd-HHmm
$monthreport = "$scriptlocation\$weekdate-$scriptname.csv"
Collect-Metering
} '5' {
$cluster = "cluster1.prd.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
Disable-Metering
$cluster = "cluster2.test.shift.com"
$nodes = Get-ClusterNode -cluster $cluster
Disable-Metering
}
}
pause
}
until ($selection -eq 'q')
# Stop transcript
stop-transcript
= Resources =
* Start and collect resourcemonitoring for all VMs in Hyper-V Cluster
* https://docs.microsoft.com/en-us/powershell/module/hyper-v/enable-vmresourcemetering?view=win10-ps
* https://searchservervirtualization.techtarget.com/tip/Understand-how-to-allocate-storage-IOPS-with-QoS-Management
* https://robertsmit.wordpress.com/2013/07/26/windows-server-2012r2-iops-resource-metering-hyper-v-ws2012r2-winserv-msftprivatecloud/
* https://irontrack.wordpress.com/2017/02/09/measuring-disk-performance-on-hyperv-vms/
* https://deploymentbunny.com/2014/03/25/powershell-is-king-simple-resource-metering-using-powershell/
* https://docs.microsoft.com/en-us/powershell/module/hyper-v/measure-vm?view=winserver2012r2-ps
* https://blog.workinghardinit.work/2014/01/08/how-to-measure-iops-of-a-virtual-machine-with-resource-metering-and-measurevm/
* https://www.veeam.com/blog/hyper-v-resource-metering-practical-examples.html
* https://devblogs.microsoft.com/scripting/use-powershell-to-configure-hyper-v-resource-metering/
//This wiki has been made possible by://