Files
PowerCLI-Example-Scripts/Modules/Recommend-Sizing/Recommend-Sizing.psm1
dmilov fb641c8a1c License PowerCLI-Examples-Scripts repository under BSD-2 Clause (#462)
As part of the VMware open source program, we have to update this repository with the correct license and copyright information.
We add the BSD-2 Clause License for this repository.
We mark all source code provided by VMware with the Copyright notice under BSD-2 Clause license.

* Update repository license to BSD 2-Clause License

* Update Copyright
2021-06-07 09:58:47 +03:00

231 lines
12 KiB
PowerShell

<#
Copyright 2021 VMware, Inc.
SPDX-License-Identifier: BSD-2-Clause
#>
function Recommend-Sizing {
<#
.NOTES
===========================================================================
Created by: Markus Kraus
Twitter: @VMarkus_K
Private Blog: mycloudrevolution.com
===========================================================================
Changelog:
2016.11 ver 1.0 Base Release
2016.11 ver 1.1 Optional Stats Collection
2016.11 ver 1.2 VM Stats from Realtime Data and new Counters
===========================================================================
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, 6.0
PowerCLI Version: PowerCLI 6.3 R1, PowerCLI 6.5 R1
PowerShell Version: 4.0, 5.0
OS Version: Windows 8.1, Server 2012 R2
===========================================================================
Keywords vSphere, ESXi, VM, Storage, Sizing
===========================================================================
.DESCRIPTION
This Function collects Basic vSphere Informations for a Hardware Sizing Recommandation. Focus is in Compute Ressources.
.Example
Recommend-Sizing -ClusterNames Cluster01, Cluster02 -Stats -StatsRange 60 -Verbose
.Example
Recommend-Sizing -ClusterNames Cluster01, Cluster02
.Example
Recommend-Sizing -ClusterNames Cluster01
.PARAMETER ClusterNames
List of your vSphere Cluser Names to process.
.PARAMETER Stats
Enables Stats Collection.
Warning: At the moment this is only fully tested with vSphere 5.5 and vSphere 6.5!
.PARAMETER StatsRange
Time Range in Minutes for the Stats Collection.
Default is 24h.
#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=$False, Position=0)]
[Array] $ClusterNames,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, Position=1, ParameterSetName = "Stats")]
[switch] $Stats,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, Position=2, ParameterSetName = "Stats")]
[int] $StatsRange = 1440
)
Begin {
if ($Stats) {
Write-Warning "Stats Collection requested.`nAt the moment this is only fully tested with vSphere 5.5 and vSphere 6.5"
[int]$TimeRange = "-" + $StatsRange
}
$Validate = $True
#region: Check Clusters
Write-Verbose "$(Get-Date -Format G) Starting Cluster Validation..."
foreach ($ClusterName in $ClusterNames) {
$TestCluster = Get-Cluster -Name $ClusterName -ErrorAction SilentlyContinue -Verbose:$False
if(!($TestCluster)){
Write-Warning "No Custer found wth Name $ClusterName!"
$Validate = $False
}
elseif ($TestCluster.count -gt 1) {
Write-Warning "Multiple Custers found wth Name $ClusterName!`nUse a List of explicit Cluster Names: Recommend-Sizing -ClusterNames Cluster01, Cluster02 "
$Validate = $False
}
}
Write-Verbose "$(Get-Date -Format G) Cluster Validation completed"
#endregion
}
Process {
$MyView = @()
if ($Validate -eq $True) {
foreach ($ClusterName in $ClusterNames) {
#region: Get Cluster Objects
Write-Verbose "$(Get-Date -Format G) Collect $ClusterName Cluster Objects..."
$Cluster = Get-Cluster -Name $ClusterName -Verbose:$False
$ClusterVMs = $Cluster | Get-VM -Verbose:$False
$ClusterVMsPoweredOn = $ClusterVMs | where {$_.PowerState -eq "PoweredOn"}
$ClusterDatastores = $Cluster | Get-Datastore -Verbose:$False
$ClusterHosts = $Cluster | Get-VMHost -Verbose:$False
$HostsAverageMemoryUsageGB = [math]::round( ($ClusterHosts | Measure-Object -Average -Property MemoryUsageGB).Average,1 )
$HostsAverageMemoryUsage = $([math]::round( (($ClusterHosts | Measure-Object -Average -Property MemoryUsageGB).Average / ($ClusterHosts | Measure-Object -Average -Property MemoryTotalGB).Average) * 100,1 ))
$HostsAverageCpuUsageMhz = [math]::round( ($ClusterHosts | Measure-Object -Average -Property CpuUsageMhz).Average,1 )
$HostsAverageCpuUsage = $([math]::round( (($ClusterHosts | Measure-Object -Average -Property CpuUsageMhz).Average / ($ClusterHosts | Measure-Object -Average -Property CpuTotalMhz).Average) * 100,1 ))
Write-Verbose "$(Get-Date -Format G) Collect $($Cluster.name) Cluster Objects completed"
#endregion
#region: CPU Calculation
Write-Verbose "$(Get-Date -Format G) Collect $($Cluster.name) CPU Details..."
$VMvCPUs = ($ClusterVMs | Measure-Object -Sum -Property NumCpu).sum
$LogicalThreads = $Cluster.ExtensionData.Summary.NumCpuThreads
$CpuCores = $Cluster.ExtensionData.Summary.NumCpuCores
$vCPUpCPUratio = [math]::round( $VMvCPUs / $LogicalThreads,1 )
Write-Verbose "$(Get-Date -Format G) Collect $($Cluster.name) CPU Details completed."
#endregion
#region: Memory Calculation
Write-Verbose "$(Get-Date -Format G) Collect $($Cluster.name) Memory Details..."
$AllocatedVMMemoryGB = [math]::round( ($ClusterVMs | Measure-Object -Sum -Property MemoryGB).sum )
$PhysicalMemory = [math]::round( $Cluster.ExtensionData.Summary.TotalMemory / 1073741824,1 )
$MemoryUsage = [math]::round( ($AllocatedVMMemoryGB / $PhysicalMemory) * 100 ,1 )
Write-Verbose "$(Get-Date -Format G) Collect $($Cluster.name) Memory Details completed"
#endregion
if ($Stats) {
#region: Creating VM Stats
Write-Verbose "$(Get-Date -Format G) Create $($Cluster.name) VM Stats..."
$VMMetrics = "disk.numberwrite.summation","disk.numberread.summation","cpu.usage.average", "mem.usage.average"
$Start = (Get-Date).AddMinutes($TimeRange)
$VMStats = Get-Stat -Realtime -Stat $VMMetrics -Entity $ClusterVMsPoweredOn -Start $Start -Verbose:$False
Write-Verbose "$(Get-Date -Format G) Create $($Cluster.name) VM Stats completed"
#endregion
#region: Creating VM Stats Report
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) VM Stats Report..."
$ReportVMPerf = @()
$ReportVMPerf = $VMStats | Group-Object -Property {$_.Entity.Name},Instance | %{
New-Object PSObject -Property @{
IOPSWriteAvg = ($_.Group | `
where{$_.MetricId -eq "disk.numberwrite.summation"} | `
Measure-Object -Property Value -Average).Average
IOPSReadAvg = ($_.Group | `
where{$_.MetricId -eq "disk.numberread.summation"} | `
Measure-Object -Property Value -Average).Average
CPUUsageAvg = ($_.Group | `
where{$_.MetricId -eq "cpu.usage.average"} | `
Measure-Object -Property Value -Average).Average
MEMUsageAvg = ($_.Group | `
where{$_.MetricId -eq "mem.usage.average"} | `
Measure-Object -Property Value -Average).Average
}
}
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) VM Stats Report completed"
#endregion
}
else {
Write-Verbose "$(Get-Date -Format G) Stats Collection skipped..."
}
#region: Create VM Disk Space Report
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) VM Disk Space Report..."
$reportDiskSpace = @()
foreach ($ClusterVM in $ClusterVMs){
$VMDKs = $ClusterVM | get-HardDisk -Verbose:$False
foreach ($VMDK in $VMDKs) {
if ($VMDK -ne $null){
[int]$CapacityGB = $VMDK.CapacityKB/1024/1024
$Report = [PSCustomObject] @{
CapacityGB = $CapacityGB
}
$reportDiskSpace += $Report
}
}
}
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) VM Disk Space Report completed"
#endregion
#region: Create Datastore Space Report
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) Datastore Space Report..."
$DatastoreReport = @($ClusterDatastores | Select-Object @{N="CapacityGB";E={[math]::Round($_.CapacityGB,2)}}, @{N="FreeSpaceGB";E={[math]::Round($_.FreeSpaceGB,2)}}, @{N="UsedSpaceGB";E={[math]::Round($_.CapacityGB - $_.FreeSpaceGB,2)}})
Write-Verbose "$(Get-Date -Format G) Process $($Cluster.name) Datastore Space Report completed"
#endregion
#region: Create Global Report
Write-Verbose "$(Get-Date -Format G) Process Global Report..."
$SizingReport = [PSCustomObject] @{
Cluster = $Cluster.name
HAEnabled = $Cluster.HAEnabled
DrsEnabled = $Cluster.DrsEnabled
Hosts = $Cluster.ExtensionData.Summary.NumHosts
HostsAverageMemoryUsageGB = $HostsAverageMemoryUsageGB
HostsAverageMemoryUsage = "$HostsAverageMemoryUsage %"
HostsAverageCpuUsageMhz = $HostsAverageCpuUsageMhz
HostsAverageCpuUsage = "$HostsAverageCpuUsage %"
PhysicalCPUCores = $CpuCores
LogicalCPUThreads = $LogicalThreads
VMs = $ClusterVMs.count
ActiveVMs = $ClusterVMsPoweredOn.count
VMvCPUs = $VMvCPUs
vCPUpCPUratio = "$vCPUpCPUratio : 1"
PhysicalMemoryGB = $PhysicalMemory
AllocatedVMMemoryGB = $AllocatedVMMemoryGB
ClusterMemoryUsage = "$MemoryUsage %"
SumVMDiskSpaceGB = [math]::round( ($reportDiskSpace | Measure-Object -Sum -Property CapacityGB).sum, 1 )
SumDatastoreSpaceGB = [math]::round( ($DatastoreReport | Measure-Object -Sum -Property CapacityGB).sum, 1 )
SumDatastoreUsedSpaceGB = [math]::round( ($DatastoreReport | Measure-Object -Sum -Property UsedSpaceGB).sum, 1 )
AverageVMIOPSWriteAvg = [math]::round( ($ReportVMPerf | Measure-Object -Average -Property IOPSWriteAvg).Average,1 )
AverageVMIOPSReadAvg = [math]::round( ($ReportVMPerf | Measure-Object -Average -Property IOPSReadAvg).Average,1 )
AverageVMCPUUsageAvg = "$([math]::round( ($ReportVMPerf | Measure-Object -Average -Property CPUUsageAvg).Average,1 )) %"
AverageVMMEMUsageAvg = "$([math]::round( ($ReportVMPerf | Measure-Object -Average -Property MEMUsageAvg).Average,1 )) %"
}
$MyView += $SizingReport
Write-Verbose "$(Get-Date -Format G) Process Global Report completed"
#endregion
}
}
Else {
Write-Error "Validation Failed! Processing Skipped"
}
}
End {
$MyView
}
}