简体   繁体   中英

Powershell - Group-Object PSObject with multiple properties

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 aa 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

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 (eg, 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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM