1

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

1 Answer 1

7

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
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.