Set-IOPSLimit.psm1
function Set-IOPSLimit { <# .NOTES =========================================================================== Created by: Markus Kraus Twitter: @VMarkus_K Private Blog: mycloudrevolution.com =========================================================================== Changelog: 2016.11 ver 2.0 Base Release =========================================================================== External Code Sources: http://www.lucd.info/2011/04/22/get-the-maximum-iops/ https://communities.vmware.com/thread/485386 =========================================================================== Tested Against Environment: vSphere Version: 5.5 U2 PowerCLI Version: PowerCLI 6.3 R1, PowerCLI 6.5 R1 PowerShell Version: 4.0, 5.0 OS Version: Windows 8.1, Server 2012 R2 Keyword: VM, IOPS, Limits =========================================================================== .DESCRIPTION Report and Set VM Disk IO Limits .Example Get-VM -Name TST* | Set-IOPSLimit -ConfigPath C:\Scripts\vSphere-Modules\Set-IOPSLimit.xml -SetLimit | ft -AutoSize .Example Get-VM -Name TST* | Set-IOPSLimit -ConfigPath C:\Scripts\vSphere-Modules\Set-IOPSLimit.xml | ft -AutoSize .PARAMETER VMs Specify the VMs .PARAMETER ConfigPath Path to XML File with Valid Configuration Example: <?xml version="1.0" encoding="utf-8"?> <Config version="1.0"> <Variable Name="Split" Value="-" /> <Variable Name="Split_Position" Value="3" /> <Bronze> <Name>B</Name> <Value>250</Value> </Bronze> <Silver> <Name>S</Name> <Value>1000</Value> </Silver> <Gold> <Name>G</Name> <Value>-1</Value> </Gold> </Config> .PARAMETER SetLimit Switch to enforce the Limits #Requires PS -Version 4.0 #Requires -Modules VMware.VimAutomation.Core, @{ModuleName="VMware.VimAutomation.Core";ModuleVersion="6.3.0.0"} #> [CmdletBinding()] param( [Parameter(Mandatory=$True, ValueFromPipeline=$True, Position=0)] [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl[]] $VMs, [Parameter(Mandatory=$True, ValueFromPipeline=$False, Position=1)] [String] $ConfigPath, [Parameter(Mandatory=$False, ValueFromPipeline=$False, Position=2)] [String] $Exclusions = "Template_*|Test_*", [Parameter(Mandatory=$False, ValueFromPipeline=$False, Position=3)] [Switch] $SetLimit ) Begin { $Validate = $True $XMLValidate = $True #region: Read XML If (Test-Path $ConfigPath) { try { $Variable = [XML] (Get-Content $ConfigPath) } catch { Write-Error "Invalid xml"; $XMLValidate = $False } } Else { Write-Error "Missing xml File"; $XMLValidate = $False } #endregion #region: Process XML Values [String] $B = $Variable.Config.Bronze.Name [Int] $B_Limit = $Variable.Config.Bronze.Value [String] $S = $Variable.Config.Silver.Name [Int] $S_Limit = $Variable.Config.Silver.Value [String] $G = $Variable.Config.Gold.Name [Int] $G_Limit = $Variable.Config.Gold.Value [String] $Split = ($Variable.Config.Variable | Where-Object {$_.Name -eq "Split"}).Value [Int] $Split_position = ($Variable.Config.Variable | Where-Object {$_.Name -eq "Split_Position"}).Value #endregion } Process { if ($XMLValidate -eq $True) { $Validate = $True #region: Filter VMs $myVMs = $VMs | where {($_ | Get-HardDisk).count -gt 0 -and ($_ | Get-HardDisk).ExtensionData.Controllerkey -ne 200} #endregion if ($null -ne $myVMs) { #region: Creating HD-Tab Write-Verbose "Starting to Create HD-Tab..." $hdTab = @{} foreach($hd in (Get-Harddisk -VM $myVMs)){ $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 and Process VM Rport Write-Verbose "Starting to Process VM Report..." $report = @() foreach ($myVM in $myVMs) { $VMHDDs = Get-HardDisk -VM $myVMs | select Name, ExtensionData, Filename, CapacityKB foreach ($VMHDD in $VMHDDs) { $row = "" | select VmName, ScsiID, Datastore, Tier, CapacityGB, CurrentIOLimit, PlannedIOLimit, IOLimitCorrect, HostSchedulerIsmClock, Processed $row.VmName = $myVM.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($Split)[$Split_position] switch ($row.Tier) { $S {$row.PlannedIOLimit = $S_Limit} $B {$row.PlannedIOLimit = $B_Limit} $G {$row.PlannedIOLimit = $G_Limit} default {Write-Error "Invalid DS name or tier identifier" ; $Validate = $False} } if ($row.VmName -match $Exclusions) {$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 $Exclusions) {$row.IOLimitCorrect = "No IO Limit Set"} elseif ($row.VmName -match $Exclusions) {$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"} $SchedulerWithReservation = (Get-AdvancedSetting -Entity $myVM.VMHost -Name Disk.SchedulerWithReservation).Value if ($SchedulerWithReservation -eq 0){ $row.HostSchedulerIsmClock = "False" } else{ $row.HostSchedulerIsmClock = "True" } $row.Processed = "False" if ($SetLimit -and $Validate -eq $True) { if ($row.IOLimitCorrect -ne "Just Right") { $VMDisk = $myVM | Get-HardDisk | where {$_.Name -eq $VmHdd.Name} if ($myVM.Name -match $Exclusions) { ## Remove Limit on Exclusions if ($VMDisk.ExtensionData.StorageIOAllocation.limit -ne -1) { $myVM | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond "-1" | Out-Null $row.Processed = "True" } } elseif ($VMDisk.Persistence -eq "independentpersistent" ) { ## Remove Limit on Raw Devices if ($VMDisk.ExtensionData.StorageIOAllocation.limit -ne -1) { $myVM | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond "-1" | Out-Null $row.Processed = "True" } } else { ## Set Limit $myVM | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $VMDisk -DiskLimitIOPerSecond $row.PlannedIOLimit | Out-Null $row.Processed = "True" if( $row.HostSchedulerIsmClock -eq "True" ){ Write-Warning "mClock Scheduler can couse unexpected Results!`nSee: http://anthonyspiteri.net/esxi-5-5-iops-limit-mclock-scheduler/" } } } } $report += $row } } #endregion if ($SetLimit -and $Validate -eq $False) {Write-Output "`n"; Write-Error "Validation Failed! VM Disk Processing Skipped"} $Report } } Else { Write-Error "XML Validation Failed! Processing Skipped" } } End { ## No End } } |