Powershell‎ > ‎VMWare CLI‎ > ‎

VM Stats


VM Stats V2


IF (Get-PSSnapin | where {$_.name -eq "VMware.VimAutomation.Core"}) 
    {write-host "VMware.VimAutomation.Core snapin already loaded"}
Else
{
    write-host "Loading VMware.VimAutomation.Core snapin"
    add-PSSnapin  VMware.VimAutomation.Core
    write-host "VMware.VimAutomation.Core snapin Loaded"
}
    
$VirtualCenters= "vmvc1","vmvc2"
#Hashtable for Tier Multiplier, lookup the Tier and return the TierMultiplier
$TierMultiplier = @{2=2; 3=1; 4=0}
#This is the percent for "Adjusted Percent Memory Commit" that a row will be highlighted in red
$ThresholdMarkCritical = 100
#This is the percent for "Adjusted Percent Memory Commit" that will cause Required RAM to be Calculated
$ThresholdCalcRequireRAM = 90
#This is the percent in decimal for "Adjusted Percent Memory Commit" that is used to Calculate Required RAM 
$DesiredAdjustedPercentMemoryCommit = .75
#This is the amount of RAM in GB that comes in a newly purchased host
$NewHostMemorySize=128
$RequiredHostsFieldName= "Required $NewHostMemorySize GB Hosts"


$smtpServer = "mail.blah.com"
$To = "Kevin Curran <kcurran@blah.com>"
$From = "AD Reporting <ADReporting@blah.com>"


foreach ($VC in $VirtualCenters)
{
    Connect-VIServer $VC
    
    $DataCenters= Get-Datacenter
    #Collect Cluster Stats for email body
    $VMStats +=foreach ($DataCenter in $DataCenters) 
    { 
        $clusters = get-cluster -Location $DataCenter.Name
        if ($clusters -eq $null) 
            {(get-vm -Location $DataCenter.Name).count | select @{Name="Name";Expression= {$DataCenter.Name}}, 
                @{Name="Hosts";Expression={((Get-VMHost -Location $DataCenter.Name) | measure ).count}},
                @{Name="VMs";Expression={(get-vm -Location $DataCenter.Name).count}},
                @{Name="Memory Total GB";Expression={[Math]::Round($(Get-VMHost -Location $_.Name | measure -Property MemoryTotalGB -sum).sum,2)}},
                @{Name="Memory Commit GB";Expression={[Math]::Round($(Get-VM -Location $_.Name | measure -Property MemoryGB -sum).sum,2)}},
                @{Name="Top Host RAM GB";Expression={[Math]::Round($(Get-VMHost -Location $_.Name | Sort-Object -Property MemoryTotalGB | select MemoryTotalGB -Last 1).MemoryTotalGB,2)}},
                @{Name="DataCenter";Expression={($DataCenter)}}
            }
        else
        {
            get-cluster -Location $DataCenter.Name | select Name, @{Name="Hosts"; Expression = {($_.ExtensionData.Host).count}}, 
                @{Name="VMs"; Expression = {(Get-VM -Location $_.Name).count}},
                @{Name="Memory Total GB";Expression={[Math]::Round($(Get-VMHost -Location $_.Name | measure -Property MemoryTotalGB -sum).sum,2)}},
                @{Name="Memory Commit GB";Expression={[Math]::Round($(Get-VM -Location $_.Name | measure -Property MemoryGB -sum).sum,2)}},
                @{Name="Top Host RAM GB";Expression={[Math]::Round($(Get-VMHost -Location $_.Name | Sort-Object -Property MemoryTotalGB | select MemoryTotalGB -Last 1).MemoryTotalGB,2)}},
                @{Name="DataCenter";Expression={($DataCenter)}}
        }   
    }
    
    Disconnect-VIServer -Confirm:$False
}


#Create a summary report to email VM to Host ratios
foreach ($Cluster in $VMStats)
{
    #Add Ratios
    $Cluster | Add-Member -membertype noteproperty -name Ratio -Value `
        $(
            try {
                "{0:n2} to 1" -f(($Cluster.VMs) / ($Cluster.Hosts))
            }    
            catch [System.DivideByZeroException] { 
                "Divide by 0!"
            }
            finally {
               # Cleanup
            }
        )
    
    #Tier is set as the 3rd character of the cluster name
    #if that is not a number this switch will adjust them
    #May consider adding Tier as a custom annotation
    #Get-Cluster cv201 | Set-Annotation -CustomAttribute "Tier" -Value 2
    $Cluster | Add-Member -membertype noteproperty -name Tier -Value $($Cluster.Name.substring(2,1))
    $Cluster.Tier =switch ($Cluster.Tier)
    {
        "F" {2}
        "L"    {3}
        "W" {3}
        "X" {3}
        #Cast Tier to int 
         default {[int]$_}
    }
    #Add Percent Memory Commit
    $Cluster | Add-Member -membertype noteproperty -name "Percent Memory Commit" -Value `
        $([Math]::Round((($Cluster."Memory Commit GB") / ($Cluster."Memory Total GB") * 100),2))
    #Now that Tier is valid calculate "Adjusted Percent Memory Commit"
    #"Adjusted Percent Memory Commit" is
    #Total VM RAM commit  / divided by
    #Total ESX Server RAM - [(Largest ESX server RAM value) x {Tier multiplier}]
    $Cluster | Add-Member -membertype noteproperty -name "Adjusted Percent Memory Commit" -Value `
        $(     
            try {
                [Math]::Round((($Cluster."Memory Commit GB" / ($Cluster."Memory Total GB" - ($Cluster."Top Host RAM GB"  * $TierMultiplier.Item($Cluster.Tier)))) * 100),2)
            }    
            catch [System.DivideByZeroException] { 
                "Divide by 0!"
            }
            finally {
               # Cleanup
            }
        )
    #Mark Critical Clusters This mark is later replaced in HTML to convert row color to red
    If ($Cluster."Adjusted Percent Memory Commit" -ge $ThresholdMarkCritical )
        {$Cluster.Name = "Critical" + $Cluster.Name}
    #Add Required RAM to reach a 75% Adjusted Percent Memory Commit
    $Cluster | Add-Member -membertype noteproperty -name "Required Ram GB" -Value `
        $(
            If ($Cluster."Adjusted Percent Memory Commit" -ge $ThresholdCalcRequireRAM)
                {[Math]::Round(($Cluster."Memory Commit GB" / $DesiredAdjustedPercentMemoryCommit ) + ($Cluster."Top Host RAM GB"  * $TierMultiplier.Item($Cluster.Tier)) - $Cluster."Memory Total GB" ,2)}
        )
    #Number of hosts to purchase to reach a 75% Adjusted Percent Memory Commit
    $Cluster | Add-Member -membertype noteproperty -name $RequiredHostsFieldName -Value `
        $(
            If ($Cluster."Required Ram GB" -ne $null)
                #Rounding up [system.math]::ceiling(3.1)
                {[Math]::ceiling($Cluster."Required Ram GB" / $NewHostMemorySize)}
        )
}



$TotalHosts = ($VMStats | Measure-Object -Sum -Property Hosts).sum
$TotalVMs = ($VMStats | Measure-Object -Sum -Property VMs).sum
$TotalRatio = "{0:n2} to 1" -f(($TotalVMs) / ($TotalHosts))

$TotalMessage = "<H2>Totals</H2>Total Hosts`: $totalHosts <br>Total VMs`: $totalVMs <br>Total Ratio`: $totalRatio <br>"
$SumaryReport= $VMStats | Group-Object -Property DataCenter | Sort Name
foreach ($RPTDataCtr in $SumaryReport)
{
    $RPTDC = switch ($RPTDataCtr.Name) 
        { 
            "LADC" {"LA"} 
            "NYDC" {"NY"} 
            "CDC" {"Chicago"}
            "FDC" {"Florida"} 
            default {$_}
        }
    $TempHTML = $null
    $SubTotalHosts = $null
    $SubTotalVMs = $null
    $SubTotalRatio = $null
    $SubTotalHosts = ($RPTDataCtr.Group | Measure-Object -Sum -Property Hosts).sum
    $SubTotalVMs = ($RPTDataCtr.Group | Measure-Object -Sum -Property VMs).sum
    #$SubTotalRatio = "{0:n2} to 1" -f(($SubTotalVMs) / ($SubTotalHosts))
    $SubTotalMemTotalGB = ($RPTDataCtr.Group | Measure-Object -Sum -Property "Memory Total GB").sum
    $SubTotalMemCommitGB = ($RPTDataCtr.Group | Measure-Object -Sum -Property "Memory Commit GB").sum
    $TempHTML= $RPTDataCtr.Group | ConvertTo-Html -Fragment -Property Name, Hosts, VMs, "Memory Total GB", "Memory Commit GB", Tier, "Top Host RAM GB", "Percent Memory Commit", "Adjusted Percent Memory Commit", "Required Ram GB", $RequiredHostsFieldName -PreContent "<b>$RPTDC</b>" | ForEach-Object {$_}
    $TempHTML = $TempHTML -Replace "</table>","<tr style=`"font-weight`: bold`;`"><td>Total</td><td>$SubTotalHosts</td><td>$SubTotalVMs</td><td>$SubTotalMemTotalGB</td><td>$SubTotalMemCommitGB</td></tr>`r`n</table>"
    $Message += $TempHTML
    #$Message+= $RPTDataCtr.Group | ConvertTo-Html -Fragment -Property Name, Hosts, VMs, Ratio -PreContent "<H2>$($RPTDataCtr.Name)</H2>" | ForEach-Object {$_}
}


#$Message= $VMStats | sort -Property Name | ConvertTo-Html 
#$Message= $VMStats | sort -Property Name | ConvertTo-Html -PreContent "Current VM Stats <H2>VM Ratios </H2>" | ForEach-Object {$_}

#Modify HTML to display clusters marked as Critical in Red
$ModifiedHTML=ForEach ($line in $Message)
{
    $line.replace('<tr><td>Critical','<tr class="Crit"><td>')
}



$PreMessage = @" 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML TABLE</title>
<style>
    BODY{background-color:white;}
    TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
    TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:MidnightBlue; color:Yellow}
    TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:PaleGoldenrod}
    TR.D0 TD {background-color: White; color: black;}
    TR.D1 TD {background-color: LawnGreen; color: black;}
    TR.Crit TD {background-color: Red; color: black;}
</style>
</head><body>

“@

$PostMessage += "<br>This script was run by " + $env:username + " on " + $env:COMPUTERNAME
$PostMessage += "<br>ScriptName: $($MyInvocation.MyCommand) "
$PostMessage += "<br>Script path: $(Split-Path -Parent $MyInvocation.MyCommand.Path)"
$PostMessage += "</body></html>"

$html = $PreMessage + $TotalMessage + $($ModifiedHTML | out-string) + $PostMessage

#Send Message
Send-MailMessage -From $From -To $To -SmtpServer $smtpServer `
    -Subject "VM Stats V2" -BodyasHTML $HTML 



Ugly script still needs work.


@"
===============================================================================
Title:         Export-VMInfo.ps1
Description:   Exports VM Information from vCenter into a .CSV file for importing into anything
Usage:         .\Export-VMInfo.ps1
Date:          04/03/2010
http://www.wooditwork.com/2010/08/16/exporting-all-that-useful-vm-information-with-powercli/
===============================================================================
"@
 
IF (Get-PSSnapin | where {$_.name -eq "VMware.VimAutomation.Core"}) 
    {write-host "VMware.VimAutomation.Core snapin already loaded"}
Else
{
    write-host "Loading VMware.VimAutomation.Core snapin"
    add-PSSnapin  VMware.VimAutomation.Core
    write-host "VMware.VimAutomation.Core snapin Loaded"
}
    
$VirtualCenters= "vmvc1","vmvc2"
$Report = @()
$ExportFilePath = "c:\temp\Export-VMInfo.csv"

Function check-even ($num) {[bool]!($num%2)}
$smtpServer = "mail.blah.com"
$To = "Kevin Curran <kcurran@blah.com>"
$From = "AD Reporting <ADReporting@blah.com>"

function Get-VMSerial
{
  param([VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]$VirtualMachine)
  $s = ($VirtualMachine.ExtensionData.Config.Uuid).Replace("-", "")
  $Uuid = "VMware-"
  for ($i = 0; $i -lt $s.Length; $i += 2)
  {
    $Uuid += ("{0:x2}" -f [byte]("0x" + $s.Substring($i, 2)))
    if ($Uuid.Length -eq 30) { $Uuid += "-" } else { $Uuid += " " }
  }

  Write-Output $Uuid.TrimEnd()
}

foreach ($VC in $VirtualCenters)
{
    Connect-VIServer $VC
        
    $VMs = Get-VM
     
    $Datastores = Get-Datastore | select Name, Id
    $VMHosts = Get-VMHost | select Name, Parent
    $VMHostDataCenter=Get-Datacenter | foreach {
        $Datacenter = $_.name
        $_ | Get-VMHost | select @{Name="VMHost";Expression={($_.Name)}}, @{Name="DataCenter";Expression={($Datacenter)}}
    } 
    
    $DataCenters= Get-Datacenter
    #Collect Cluster Stats for email body
    $VMsPerCLuster +=foreach ($DataCenter in $DataCenters) 
    { 
        $clusters=get-cluster -Location $DataCenter.Name
        if ($clusters -eq $null) 
            {(get-vm -Location $DataCenter.Name).count | select @{Name="Name";Expression= {$DataCenter.Name}}, 
                @{Name="Hosts";Expression={((Get-VMHost -Location $DataCenter.Name) | measure ).count}},
                @{Name="VMs";Expression={(get-vm -Location $DataCenter.Name).count}},
                @{Name="DataCenter";Expression={($DataCenter)}}
            }
        else
        {
            get-cluster -Location $DataCenter.Name | select Name, @{Name="Hosts"; Expression = {($_.ExtensionData.Host).count}}, 
                @{Name="VMs"; Expression = {(Get-VM -Location $_.Name).count}},
                @{Name="DataCenter";Expression={($DataCenter)}}
        }    
    }
    #collect VM data for attached list of vms
    ForEach ($VM in $VMs) {
        $counter ++
        Write-Host $counter $VM.name
        $VMView = $VM | Get-View
        $Annotation = $vm | Get-Annotation
        $VMInfo = {} | Select VMName,Powerstate,OS,IPAddress,ToolsStatus,Host,
            Cluster,Datacenter,Datastore,inSRMResourcePool,NumCPU,MemMb,ProvisionedSpaceGB,
            UsedSpaceGB,DiskGb,DiskFree,DiskUsed,Notes,BusinessOwner,
            CreationDate,DownTimeWindow,PrimarySysAdmin,Tier,SerialNumber
        $VMInfo.VMName = $vm.name
        $VMInfo.Powerstate = $vm.Powerstate
        $VMInfo.OS = $vm.Guest.OSFullName
        $VMInfo.IPAddress = $vm.Guest.IPAddress[0]
        $VMInfo.ToolsStatus = $VMView.Guest.ToolsStatus
        $VMInfo.Host = $vm.VMhost.name
        $VMInfo.Cluster = $vm.VMhost.Parent.Name
        $VMInfo.Datacenter = ($VMHostDataCenter | where {$_.VMHost -eq $vm.VMhost.name} | select DataCenter).DataCenter
        $VMInfo.Datastore = ($Datastores | where {$_.ID -match ($vmview.Datastore | Select -First 1).Value}).Name
        $VMInfo.inSRMResourcePool = $vm.ResourcePool.Name -like "*SRM*"
        $VMInfo.NumCPU = $vm.NumCPU
        $VMInfo.MemMb = [Math]::Round(($vm.MemoryMB),2)
        $VMInfo.ProvisionedSpaceGB = [Math]::Round($vm.ProvisionedSpaceGB)
        $VMInfo.UsedSpaceGB = [Math]::Round($vm.UsedSpaceGB)
        $VMInfo.DiskGb = [Math]::Round((($vm | get-harddisk | Measure-Object -Property CapacityKB -Sum).Sum * 1KB / 1GB),2)
        $VMInfo.DiskFree = [Math]::Round((($vm.Guest.Disks | Measure-Object -Property FreeSpace -Sum).Sum / 1GB),2)
        $VMInfo.DiskUsed = $VMInfo.DiskGb - $VMInfo.DiskFree
        $VMInfo.Notes = $vm.Notes
        $VMInfo.BusinessOwner = ($Annotation | where {$_.Name -eq "Business Owner"}).value
        $VMInfo.CreationDate = ($Annotation | where {$_.Name -eq "Creation Date"}).value
        $VMInfo.DownTimeWindow = ($Annotation | where {$_.Name -eq "Down Time Window"}).value
        $VMInfo.PrimarySysAdmin = ($Annotation | where {$_.Name -eq "Primary SysAdmin"}).value
        $VMInfo.Tier = ($Annotation | where {$_.Name -eq "Tier"}).value
        $VMInfo.SerialNumber = Get-VMSerial $vm
        $Report += $VMInfo
    }
    Disconnect-VIServer -Confirm:$False
}

#Export VM List Report to a File to attach to email
$Report = $Report | Sort-Object VMName
IF ($Report -ne "") {
    $report | Export-Csv $ExportFilePath -NoTypeInformation
}



#Create a summary report to email VM to Host ratios
#Add Ratios
$VMStats=$VMsPerCLuster | Select DataCenter, Name, Hosts, VMs, @{Name="Ratio"; Expression = {"{0:n2} to 1" -f(($_.VMs) / ($_.Hosts)) }}
$TotalHosts = ($VMStats | Measure-Object -Sum -Property Hosts).sum
$TotalVMs = ($VMStats | Measure-Object -Sum -Property VMs).sum
$TotalRatio = "{0:n2} to 1" -f(($TotalVMs) / ($TotalHosts))

$TotalMessage = "<H2>Totals</H2>Total Hosts`: $totalHosts <br>Total VMs`: $totalVMs <br>Total Ratio`: $totalRatio <br>"
$SumaryReport= $VMStats | Group-Object -Property DataCenter | Sort Name
foreach ($RPTDataCtr in $SumaryReport)
{
    $RPTDC = switch ($RPTDataCtr.Name) 
        { 
            "LADC" {"LA"} 
            "NYDC" {"NY"} 
            "CDC" {"Chicago"}
            "FDC" {"Florida"} 
            default {$_}
        }
    $TempHTML = $null
    $SubTotalHosts = $null
    $SubTotalVMs = $null
    $SubTotalRatio = $null
    $SubTotalHosts = ($RPTDataCtr.Group | Measure-Object -Sum -Property Hosts).sum
    $SubTotalVMs = ($RPTDataCtr.Group | Measure-Object -Sum -Property VMs).sum
    $SubTotalRatio = "{0:n2} to 1" -f(($SubTotalVMs) / ($SubTotalHosts))
    $TempHTML= $RPTDataCtr.Group | ConvertTo-Html -Fragment -Property Name, Hosts, VMs, Ratio -PreContent "<b>$RPTDC</b>" | ForEach-Object {$_}
    $TempHTML = $TempHTML -Replace "</table>","<tr style=`"font-weight`: bold`;`"><td>Total</td><td>$SubTotalHosts</td><td>$SubTotalVMs</td><td>$SubTotalRatio</td></tr>`r`n</table>"
    $Message += $TempHTML
    #$Message+= $RPTDataCtr.Group | ConvertTo-Html -Fragment -Property Name, Hosts, VMs, Ratio -PreContent "<H2>$($RPTDataCtr.Name)</H2>" | ForEach-Object {$_}
}


#$Message= $VMStats | sort -Property Name | ConvertTo-Html 
#$Message= $VMStats | sort -Property Name | ConvertTo-Html -PreContent "Current VM Stats <H2>VM Ratios </H2>" | ForEach-Object {$_}

$ModifiedHTML=ForEach ($line in $Message)
{
    $counter++
    if (check-even $counter)
    {$line.replace('<tr><td>','<tr class="d0"><td>')}
    Else
    {$line.replace('<tr><td>','<tr class="d1"><td>')}
}



$PreMessage = @" 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML TABLE</title>
<style>
    BODY{background-color:white;}
    TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
    TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:MidnightBlue; color:Yellow}
    TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:PaleGoldenrod}
    TR.D0 TD {background-color: White; color: black;}
TR.D1 TD {background-color: LawnGreen; color: black;}
</style>
</head><body>

“@

$PostMessage += "<br>This script was run by " + $env:username + " on " + $env:COMPUTERNAME
$PostMessage += "<br>ScriptName: $($MyInvocation.MyCommand) "
$PostMessage += "<br>Script path: $(Split-Path -Parent $MyInvocation.MyCommand.Path)"
$PostMessage += "</body></html>"

$html = $PreMessage + $TotalMessage + $($ModifiedHTML | out-string) + $PostMessage

#Send Message
Send-MailMessage -From $From -To $To -SmtpServer $smtpServer `
-Subject "VM Ratios" -BodyasHTML $HTML -Attachments $ExportFilePath







Comments