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