I have written a PowerCLI script to retrieve relevant information plus usage stats for the previous month for our VM's and output it a csv but it's painfully slow. Can anyone suggest any improvements that could help speed up the report.
I'm fairly new to powershell/PowerCLI so any help would be gratefully received
$todayMidnight = (Get-Date -Hour 0 -Minute 0 -Second 0).AddMinutes(-1)
$EndOfLastMonth = (Get-Date -Year (get-date).Year -Month (get-date).Month -Day 1 -Hour 0 -Minute 0 -Second 0).AddMinutes(-1)
$FirstofLastMonth = $EndOfLastMonth.AddMonths(-1)
$workingDays = "Monday","Tuesday","Wednesday","Thursday","Friday"
$dayStart = New-Object DateTime(1,1,1,8,0,0)
$dayEnd = New-Object DateTime(1,1,1,18,0,0)
$CSVFile = Read-Host "Enter Filename for csv"
$Report = @()
Connect-VIServer "VCServer" | Out-Null
$ServerList = Get-VM | Where-Object {$_.VMHost.Name -ne "192.168.106.161" -and $_.PowerState -eq "PoweredOn" } | Sort-Object Name
$Counter = 1
foreach ($Server in $ServerList) {
$VMInfo = {} | select Name, OS, VMHost, IPAddress, NumCPU, TotalMemMB, AvgMemPcnt, MaxMemPcnt, AvgCPUMhz, AvgCPUPcnt, MaxCPUPcnt
$VMInfo.name = $Server
$MaxCPUPcnt = get-vm $Server | Get-Stat -Stat cpu.usage.average -IntervalSecs 1 |
Where-Object { $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} |
Measure-Object value -Max | select Maximum
$MaxMemPcnt = get-vm $Server | Get-Stat -Stat mem.usage.average -IntervalSecs 1 |
Where-Object { $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} |
Measure-Object value -Max | select Maximum
$AvgCPUMhz = get-vm $Server | Get-Stat -Stat cpu.usagemhz.average -IntervalMins 5 |
Where-Object { $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} |
Measure-Object value -Average | select Average
$AvgCPUPcnt = get-vm $Server | Get-Stat -Stat cpu.usage.average -IntervalMins 5 |
Where-Object { $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} |
Measure-Object value -Average | select Average
$AvgMemPcnt = get-vm $Server | Get-Stat -Stat mem.usage.average -IntervalMins 5 |
Where-Object { $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} |
Measure-Object value -Average | select Average
$VMinfo.MaxCPUPcnt = [math]::round($MaxCPUPcnt.Maximum,2)
$VMinfo.MaxMemPcnt = [math]::round($MaxMemPcnt.Maximum,2)
$VMinfo.AvgCPUMhz = [math]::round($AvgCPUMhz.Average,2)
$VMInfo.AvgCPUPcnt = [math]::round($AvgCPUPcnt.Average,2)
$VMInfo.AvgMemPcnt = [math]::round($AvgMemPcnt.Average,2)
$TotalMemMB = get-vm $Server | select MemoryMB
$VMInfo.TotalMemMB = $TotalMemMB.MemoryMb
$VMInfo.VMHost = (get-vm gbvc0007 | Get-VMHost).name
$VMInfo.OS = (Get-VM $Server | Get-View).summary.config.GuestFullName
$VMInfo.IPAddress = (Get-VM $Server | Get-VIew).summary.guest.ipaddress
$VMInfo.NumCPU = (Get-VM $Server | Get-VIew).summary.config.NumCPU
$Report += $VMInfo
$Counter++
}
clear
$Report | ft -AutoSize
$Report | Export-Csv -Path $CSVFile
Disconnect-VIServer -Server * -Confirm:$false
Well, first of all, you would want to do:
$vm = get-vm $Server
and work with that afterwards, so you would not need to query the server one extra time for each of the operations. Also, I'm not aware of how the get-stat works, but if you could pull all the stats you need for a VM to a variable in just one call to the server, you could later easily filter out everything you need, saving a lot of time potentially, something like this:
$vm = get-vm $Server
$vm | Get-Stat -Stat mem.usage.average,cpu.usage.average,cpu.usagemhz.average
And you could easily get something out of the variable you already have like:
$vm.MemoryMB or probably something like $vm.GuestID
you should take a look here - http://www.virtualizationadmin.com/articles-tutorials/general-virtualization-articles/use-powercli-quick-stats-part2.html
As for the general approach, i would suggest you use something like PoshRSJob to parallel out the execution of your foreach loop, that would improve the time it takes for your script to run drasticly, the only caveat is that you would need to authenticate in each RSJob, which might be an issue.