Today i would like you show another way of using Group-object cmdlet. Let’s say you want to obtain powered off, powered on and suspended virtual machines utilizing PowerCLI. Not a big deal right ? I was helping out a friend of mine lately and he had to work on two loops, one for suspended vms, and other for running and powered off vms. So normally, there is not much to talk about here, just assign two variables, the two sets. We can start from beginning so:
1 2 3 4 |
$PoweredOnVMs = get-vm |Where-Object -Property PowerState -Value PoweredOn -EQ $PoweredOffVMs = get-vm |Where-Object -Property PowerState -Value PoweredOff -EQ $SuspendedVMs = get-vm |Where-Object -Property PowerState -Value Suspended -EQ $NotSuspendedVMs= $PoweredOffVMs + $PoweredOnVM |
There is nothing wrong in general with this approach, i doubt you would even feel much speed difference if you would do it nicer for the VMs. New PowerCLI is already well optimized, but there are still some cases where you want to optimize this.
Optimizing
We would start from using filtering. We would do the query/get once, and then filter it three times:
1 2 3 4 5 |
$VMS = get-vm $PoweredOnVMs = $VMS |Where-Object -Property PowerState -Value PoweredOn -EQ $PoweredOffVMs = $VMS |Where-Object -Property PowerState -Value PoweredOff -EQ $NotSuspendedVMs = $PoweredOnVMs + $PoweredOffVMs $SuspendedVMs = $VMS |Where-Object -Property PowerState -Value Suspended -EQ |
So yeah, now, it’s much faster, we are querying it now just 1 time, instead of 3 times. Remember that the get-vm here is just an example, i can already hear you scream : Greg… just use the server side filtering using view properties. But what is also making it, you know.. ‘pretty’ is the way we assign them. What if you could do it just in 1 line ?
1 |
$vms = Get-vm | Group-Object -Property { switch -regex ($_.powerstate) { "PoweredOn|PoweredOff" { "NotSuspended"; Break } "Suspended" { "Suspended" }}} -AsHashTable -AsString |
Although in one line it can look bit cryptic, once expanded it is clear.
Group-Object it like it’s hot : done
From now on you have $vms.Suspended and $vms.NotSuspended ,so if you need to perform now two loops you have your two containers/buckets with the right objects. Powershell is just great!
What makes this possible? We used a switch parameter from Group-Object called AsHashTable. In this case we don’t need -AsString parameters, it’s good to keep this in mind when accessing your grouped objects sets using dot notation. In this case ‘Suspended’ and ‘NotSuspended’ are strings. There is no need to add the -AsString. In case of grouping by other property that is not string, that’s when you would need it.
Calculated property for Group-Object
We set it either to value ‘Suspended’ or ‘NotSuspended’ based on the PowerState property value. We are using switch with -regex parameter so that we don’t have to type two options (1 for poweron, 1 for poweroff).
In my opinion those are the tiny things that make your code nicer/easier to to maintain/read etc.
Summary
PS. Since you were brave enough to read until here, you might also want to check an article about Powershell Hashtables as we were using them here.