Reputation: 918
I'm trying to take an array of PSObjects similar to
@{BakId=27; Name=DB_A; Lsn=123; File=A_01; Size=987}
@{BakId=28; Name=DB_B; Lsn=456; File=B_01; Size=876}
@{BakId=28; Name=DB_B; Lsn=456; File=B_02; Size=765}
@{BakId=28; Name=DB_B; Lsn=456; File=B_03; Size=654}
And create a new grouped object that removes redundant header info.
BakId Lsn Name Files
27 123 DB_A {@{File=A_01.bak;Size=777}}
28 456 DB_B {@{File=B_01.bak;Size=888}, @{File=B_02.bak;Size=999}, ...}
I tried using group-object but can only get it to work for one property. (all grouped properties go into Group.Name as a a string of comma separated values.)
This is the best I've come up with, but feels hacky.
$list | Group-Object -Property BakId | % {
$BakId = $_.Name
$Lsn = $_.Group[0].Lsn # <--- is there a better way than this?
$Name = $_.Group[0].Name # <--- Ditto
$Files = $_.Group | Select-Object -Property SequenceNumber, Size
Write-Output (New-Object -TypeName PSObject -Property @{ BakId=$BakId;Files = $Files })
}
Is there a better way?
Thanks
Upvotes: 1
Views: 6834
Reputation: 437111
You can simplify the approach to constructing the output objects by using a single Select-Object
call with calculated properties, and, relying on the order of the grouping properties, access their group-specific values via the .Values
collection:
$list | Group-Object -Property BakId, Lsn, Name |
Select-Object @{n='BakId'; e={ $_.Values[0] }},
@{n='Lsn'; e={ $_.Values[1] }},
@{n='Name'; e={ $_.Values[2] }},
@{n='Files'; e={ $_.Group | Select-Object File, Size }}
Note:
$_.Values[<ndx>]
takes the place of $_.Group[0].<name>
in your approach; note that the latter only makes sense for the actual grouping properties, because any others will not be uniform throughout the group.
The .Values
collection ([System.Collections.ArrayList]
) on each group object output from Group-Object
([Microsoft.PowerShell.Commands.GroupInfo]
instance) contains that group's shared grouping-property values as-is (original type), in the order specified.
By contrast, property .Name
contains the stringified combination of all grouping-property values: a string containing a comma-separated list.
Unfortunately, such details are currently missing from Get-Help Group-Object
.
If you wanted to avoid having to repeat the grouping properties (e.g., in preparation for writing a function wrapper; PSv3+):
$props = 'BakId', 'Lsn', 'Name'
$list | Group-Object -Property $props | ForEach-Object {
$propDefs = [ordered] @{}
foreach ($i in 0..($props.Length-1)) { $propDefs.[$props[$i]] = $_.Values[$i] }
$propDefs.Files = $_.Group | Select-Object File, Size
New-Object PSCustomObject -Property $propDefs
}
Upvotes: 7