Jume - My Virtualization Blog
Some short PowerShell tips #2
Tip 3:
PS H:\> Get-Help Group-Object NAME Group-Object SYNTAX Group-Object [[-Property] <Object[]>] [-NoElement] [-AsHashTable] [-AsString] [-InputObject <psobject>] [-Culture < string>] [-CaseSensitive] [<CommonParameters>] ALIASES group
That does Group-Object do? It groups your array of objects together based on the same value on a property in that array. It does it very efficient and also very fast: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/group-object?view=powershell-6
For example, I want to run some actions against my PoweredOn VMs and some other actions on my PoweredOff VMs. I can group them together based on power state and run actions on it. To make it simple, I group them and only care for the amount of VMs:
PS C:\> $AllVMsGrouped = Get-VM | Group-Object -Property "PowerState" PS C:\> $AllVMsGrouped Count Name Group ----- ---- ----- 118 PoweredOff {…} 10441 PoweredOn {…} PS C:\>
By default, the Group-Object returns a table with the count of objects in a group, the unique name and the group (all the objects in that group). And I have the results! Now I can loop through the group, or pipe the whole group to another cmdlet.
When working with a large dataset the speed difference can be significant. Here is a script that does the same and measures the time it takes to process the different methods. Group-Object is by far the fastest.
# Connect to (all) your vCenter servers here $TimesToRun = 5 # Select how many times to run the test $SecondsBetweenTests = 20 # Select how long to wait before starting the next test $IfTimeResults = @() $WhereTimeResults = @() $GroupingTimeResults = @() $AdvGroupingTimeResults = @() # Loop through TimesToRun for ($i = 1; $i -lt $TimesToRun + 1; $i++) { Write-Host "Running test $($i)..." $VMs = Get-VM # Every run ensures fresh data to prevent caching Start-Sleep $SecondsBetweenTests # This prevents starting the measurement before the previous command finishes # The if method $IfTime = Measure-Command { $PoweredOff = 0 $PoweredOn = 0 foreach ($VM in $VMs) { if ($VM.PowerState -eq 0) {$PoweredOff += 1} if ($VM.PowerState -eq 1) {$PoweredOn += 1} } write-host "PoweredOff: $($PoweredOff)" write-host "PoweredOn: $($PoweredOn)" } $IfTimeResults += $IfTime Start-Sleep $SecondsBetweenTests # The Where-Object method $WhereTime = Measure-Command { write-host "PoweredOff: $(($VMs | Where-Object{$_.PowerState -eq 'PoweredOff'}).count)" write-host "PoweredOn: $(($VMs | Where-Object{$_.PowerState -eq 'PoweredOn'}).count)" } $WhereTimeResults += $WhereTime Start-Sleep $SecondsBetweenTests # The Group-Object method $GroupingTime = Measure-Command { $VMsGrouped = $VMs | Group-Object -Property "PowerState" write-host "PoweredOff: $(($VMsGrouped | Where-Object {$_.Name -eq 'PoweredOff'}).Count)" write-host "PoweredOn: $(($VMsGrouped | Where-Object {$_.Name -eq 'PoweredOn'}).Count)" } $GroupingTimeResults += $GroupingTime Start-Sleep $SecondsBetweenTests # Another Group-Object method $AdvGroupingTime = Measure-Command { $AdvVMsGrouped = $VMs | Group-Object -Property "PowerState" -AsHashTable -AsString write-host "PoweredOff: $(($AdvVMsGrouped.PoweredOff).Count)" write-host "PoweredOn: $(($AdvVMsGrouped.PoweredOn).Count)" } $AdvGroupingTimeResults += $AdvGroupingTime } # Write the result of the tests Write-Host "IfTimeResults: $([math]::Round(($IfTimeResults | Measure-Object -Average -Property TotalMilliseconds).Average,1))" Write-Host "WhereTimeResults: $([math]::Round(($WhereTimeResults | Measure-Object -Average -Property TotalMilliseconds).Average,1))" Write-Host "GroupingTimeResults: $([math]::Round(($GroupingTimeResults | Measure-Object -Average -Property TotalMilliseconds).Average,1))" Write-Host "AdvGroupingTimeResults: $([math]::Round(($AdvGroupingTimeResults | Measure-Object -Average -Property TotalMilliseconds).Average,1))"
PS H:\> $AdvVMsGrouped = $VMs | Group-Object -Property "PowerState" -AsHashTable PS H:\> $AdvVMsGrouped.GetEnumerator().Name | Get-Member TypeName: VMware.VimAutomation.ViCore.Types.V1.Inventory.PowerState PS H:\> $AdvVMsGrouped = $VMs | Group-Object -Property "PowerState" -AsHashTable -AsString PS H:\> $AdvVMsGrouped.GetEnumerator().Name | Get-Member TypeName: System.String
And now time for the results. I ran mine against an enterprise environment with 8 vCenters, so lot's of VMs. The results are all in milliseconds:
WhereTimeResults: 45818.8
GroupingTimeResults: 440.6
AdvGroupingTimeResults: 322.6
While all give the same results, the last one is the fastest!!!
That's it for now. Thanks for reading and if you want to get updates, please subscribe. Please share this post and let me know your results.
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
Comments