Skip to content

Instantly share code, notes, and snippets.

@vMarkusK
Last active August 10, 2016 14:28
Show Gist options
  • Save vMarkusK/24e94c6daf77b38dec7e to your computer and use it in GitHub Desktop.
Save vMarkusK/24e94c6daf77b38dec7e to your computer and use it in GitHub Desktop.
Reports vSphere VM disks related to Datastores and Max IOPs
<#
.NOTES
===========================================================================
Created by: Markus Kraus
Twitter: @vMarkus_K
Private Blog: mycloudrevolution.com
Organization: Vater Operations GmbH
Organization Site: vater-cloud.de
===========================================================================
Changelog:
2016.03 ver 1.0 Base Release
2016.03 ver 1.1 Added VM Limit-Exclusion by Name
2016.04 ver 1.2 Added Disk Limit-Exclusion for "Independent Persistent" Disks
2016.08 ver 1.3 Added Format and Misconfiguration Report
===========================================================================
.DESCRIPTION
This will Create a IOPS Report
#Requires -Modules VMware.VimAutomation.Core, @{ModuleName="VMware.VimAutomation.Core";ModuleVersion="6.3.0.0"}
#>
#region: Load VMware Snapin
if (!(Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue)) {
if (!(Add-PSSnapin -PassThru VMware.VimAutomation.Core)) {
# Error out if loading fails
Write-Error "`nERROR: Cannot load the VMware Snapin. Is the PowerCLI installed?"
Exit
}
}
#endregion
#region: Global Definitions
$VIServer = "your-vCenter.lan.local"
[int]$TimeRange = "-10080" ## -10080 is one Week
[int]$B_Limit = "250"
[int]$S_Limit = "1000"
[int]$G_Limit = "-1"
$Unlimited = "VEEAM*||MON*|"
$entity = "Cluster" ## Cluster or Folder
$FolderName = "myFolder"
$ClusterName = @("Cluster01","Cluster02")
#endregion
#region: vCenter Connection
Write-Output "Starting to Process vCenter Connection to $VIServer ..."
$OpenConnection = $global:DefaultVIServers | where { $_.Name -eq $VIServer }
if($OpenConnection.IsConnected) {
Write-Output "vCenter is Already Connected..."
$VIConnection = $OpenConnection
} else {
Write-Output "Connecting vCenter..."
$VIConnection = Connect-VIServer -Server $VIServer
}
if (-not $VIConnection.IsConnected) {
Write-Error "`nError: vCenter Connection Failed"
Exit
}
#endregion
#region: Creating VM Array
Write-Output "Starting to Create VM Array by Entity $entity..."
if ($entity -eq "Folder") {
$VMs = get-folder -Name $FolderName | Get-VM | where {$_.PowerState -eq "PoweredOn" -and ($_ | Get-HardDisk).count -gt 0 -and ($_ | Get-HardDisk).ExtensionData.Controllerkey -ne 200}
}
elseif ($entity -eq "Cluster") {
$VMs = get-Cluster -Name $ClusterName | Get-VM | where {$_.PowerState -eq "PoweredOn" -and ($_ | Get-HardDisk).count -gt 0 -and ($_ | Get-HardDisk).ExtensionData.Controllerkey -ne 200}
}
else {
Write-Error "Error: No correct Entity Choosen"
Exit
}
#endregion
#region: Creating Metrics
Write-Output "Starting to Create Metrics..."
$metrics = "virtualDisk.numberReadAveraged.average","virtualDisk.numberWriteAveraged.average"
$start = (Get-Date).AddMinutes($TimeRange)
$stats = Get-Stat -Stat $metrics -Entity $vms -Start $start
#endregion
#region: Creating HD-Tab
Write-Output "Starting to Create HD-Tab..."
$hdTab = @{}
foreach($hd in (Get-Harddisk -VM $vms)){
$controllerKey = $hd.Extensiondata.ControllerKey
$controller = $hd.Parent.Extensiondata.Config.Hardware.Device | where{$_.Key -eq $controllerKey}
$hdTab[$hd.Parent.Name + "/scsi" + $controller.BusNumber + ":" + $hd.Extensiondata.UnitNumber] = $hd.FileName.Split(']')[0].TrimStart('[')
}
#endregion
#region: Creating Reports
Write-Output "Starting to Process IOPS Report..."
$reportPerf = @()
$reportPerf = $stats | Group-Object -Property {$_.Entity.Name},Instance | %{
New-Object PSObject -Property @{
VM = $_.Values[0]
Disk = $_.Values[1]
IOPSMax = ($_.Group | `
Group-Object -Property Timestamp | `
%{$_.Group[0].Value + $_.Group[1].Value} | `
Measure-Object -Maximum).Maximum
Datastore = $hdTab[$_.Values[0] + "/"+ $_.Values[1]]
}
}
Write-Output "Starting to Process VM Report..."
$report = @()
foreach ($Vm in $Vms) {
$VmHdds = Get-HardDisk -VM $Vm | select Name, ExtensionData, Filename, CapacityKB
foreach ($VmHdd in $VmHdds) {
$row = "" | select VmName, ScsiID, Datastore, Tier, CapacityGB, CurrentIOLimit, PlannedIOLimit, IOLimitCorrect, MaxIOPS, HitPlannedIOLimit
$row.VmName = $Vm.Name
$row.ScsiID = $([string]$VmHdd.extensiondata.controllerkey).substring(3,1) +":"+ $([string]$VmHdd.extensiondata.unitnumber)
$row.Datastore = $($VmHdd.Filename.TrimStart("[")).split("]")[0]
$row.Tier = $row.Datastore.Split("-")[3]
switch ($row.Tier) {
"S" {$row.PlannedIOLimit = $S_Limit}
"B" {$row.PlannedIOLimit = $B_Limit}
"G" {$row.PlannedIOLimit = $G_Limit}
default {$row.PlannedIOLimit = "Invalid DS name or tier identifier"}
}
if ($row.VmName -match $Unlimited) {$row.PlannedIOLimit = -1}
elseif ($VmHdd.ExtensionData.Backing.DiskMode -eq "independent_persistent") {$row.PlannedIOLimit = -1}
$row.CapacityGB = [Math]::round(($VmHdd.capacitykb / 1024 / 1024),2)
$row.CurrentIOlimit = $VmHdd.ExtensionData.StorageIOAllocation.limit
if ($row.CurrentIOLimit -eq -1 -and $row.PlannedIOLimit -ne -1 -and $row.VmName -notmatch $Unlimited) {$row.IOLimitCorrect = "No IO Limit Set"}
elseif ($row.VmName -match $Unlimited) {$row.IOLimitCorrect = "Fixed Unlimited"}
elseif ($VmHdd.ExtensionData.Backing.DiskMode -eq "independent_persistent") {$row.IOLimitCorrect = "Fixed Unlimited"}
elseif ($row.CurrentIOLimit -gt $row.PlannedIOLimit) {$row.IOLimitCorrect = "Too High"}
elseif ($row.CurrentIOLimit -lt $row.PlannedIOLimit) {$row.IOLimitCorrect = "Too Low"}
else {$row.IOLimitCorrect = "Just Right"}
$row.MaxIOPS = ($reportPerf | where {$_.VM -eq $row.VmName -and $_.Disk -eq "scsi" + $row.ScsiID}).IOPSMax
if ($row.MaxIOPS -ge $row.PlannedIOLimit -and $row.PlannedIOLimit -ne "-1" ) {$row.HitPlannedIOLimit = "YES"}
else {$row.HitPlannedIOLimit = "NO"}
$report += $row
### Uncomment the following Lines and this script will set the IO Limit for VMDKs during execution
<# if ($row.IOLimitCorrect -ne "Just Right") {
$VMDisk = $VM | Get-HardDisk | where {$_.Name -eq $VmHdd.Name}
if ($VM.Name -match $Unlimited) {
Write-Output "VM Limit Exclusion Found!"
if ($VMDisk.ExtensionData.StorageIOAllocation.limit -ne -1) {
Write-Output " Disk IOPS Limit needs to removed..."
$Vm | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond "-1"
}
else {
Write-Output " Disk IOPS Limit already unset..."
}
}
elseif ($VMDisk.Persistence -eq "independentpersistent" ) {
Write-Warning "`nWARNING: RAW Device Found!"
if ($VMDisk.ExtensionData.StorageIOAllocation.limit -ne -1) {
Write-Output " Disk IOPS Limit needs to removed..."
$Vm | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond "-1"
}
else {
Write-Output " Disk IOPS Limit already unset..."
}
}
else {
Write-Output "Disk IOPS Limit needs to be set..."
$Vm | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond $row.PlannedIOLimit
}
} ### Uncomment until here
#>
}
}
$VMsHit = @()
$VMsHit = ($Report | where {$_.HitPlannedIOLimit -eq "YES"}).VmName
$VMsMisC = @()
$VMsMisC = ($Report | where {$_.CurrentIOLimit -ne $_.PlannedIOLimit}).VmName
$reportHIT = @()
foreach ($VMHit in $VMsHit) {
$reportHIT += $report | where {$_.VmName -like $VMHit}
}
$reportMisC = @()
foreach ($VMMisC in $VMsMisC) {
$reportMisC += $report | where {$_.VmName -like $VMMisC}
}
Write-Output "`nReport of VMs with possible violation:"
$reportHIT | ft -AutoSize
Write-Output "`nReport of VMs with Misconfiguration:"
$reportMisC | ft -AutoSize
Write-Output "`nReport of all VMs:"
$Report | ft -AutoSize
#endregion
@vMarkusK
Copy link
Author

Changelog:  
2016.03 ver 1.0 Base Release 
2016.03 ver 1.1 Added VM Limit-Exclusion by Name
2016.04 ver 1.2 Added Disk Limit-Exclusion for "Independent Persistent" Disks
2016.08 ver 1.3 Added Format and Misconfiguration Report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment