0

I know there's a number of posts about expanding a single property and hopefully this is an easy one but my output looks like this as a result of a

select-string -simplematch
@{Brand=Volkswagen; Model=Passat}
@{Brand=Ford; Model=Mondeo}

But how do I expand both properties and get the output to look like this please?

Volkswagen, Passat
Ford, Mondeo

When I do a select-object * I get the below but I cant seem to get just the values

IgnoreCase : True
Linenumber : 1
Line : @{Brand=Volkswagen; Model=Passat}
Filename : InputStream
Path : InputStream
Pattern : @{Brand=Volkwagen; Model=Passat}
Context :
Match : {}}

IgnoreCase : True
Linenumber : 2
Line : @{Brand=Ford; Model=Mondeo}
Filename : InputStream
Path : InputStream
Pattern : @{Brand=Ford; Model=Mondeo}
Context :
Match : {}}

shA.t
  • 16,580
  • 5
  • 54
  • 111
kkp0897
  • 19
  • 1
  • 1
  • 1
    I commend to your attention the [documentation for `Select-Object`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object?view=powershell-7.1), specifically the `-ExpandProperty` parameter. – Jeff Zeitlin Mar 03 '21 at 12:39

3 Answers3

2

Don't do select-string on a collection of PsObjects, because that cmdlet is designed for finding text in strings and files..
Select-Object -ExpandProperty lets you expand one property, not all. If you want output like that, loop over the objects in the array and combine the properties the way you want them into a string.

Assume your array is like this:

$theCarCollection = [PsCustomObject]@{Brand='Volkswagen'; Model='Passat'},
                    [PsCustomObject]@{Brand='Ford'; Model='Mondeo'}

Then format the output by looping over the objects and selecting the properties you need

($theCarCollection | ForEach-Object { '{0}, {1}' -f $_.Brand, $_.Model }) -join [environment]::NewLine

which will output:

Volkswagen, Passat
Ford, Mondeo
Theo
  • 57,719
  • 8
  • 24
  • 41
  • Thanks but I have hundreds of records in two different files which I'm doing the match on so the array will not work as I don't have the ability to make changes to the input files – kkp0897 Mar 03 '21 at 13:57
  • 1
    @kkp0897 Then explain what these files are.. CSV perhaps? – Theo Mar 03 '21 at 14:06
0

may be somthing lie this :

Select-String -Path "C:\temp\test.txt" -Pattern "test" | select line -ExpandProperty line
Esperento57
  • 16,521
  • 3
  • 39
  • 45
  • Thanks but no that did not work, it just returned the following again @{Brand=Volkswagen; Model=Passat} @{Brand=Ford; Model=Mondeo} – kkp0897 Mar 03 '21 at 13:54
0

To complement Theo's helpful answer:

tl;dr:

# Note the use of -PipelineVariable obj and the use of $obj later.
PS> Write-Output -PipelineVariable obj (
      [pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }, 
      [pscustomobject] @{ Brand = 'Ford'; Model = 'Mondeo' }
    ) |
      Select-String -SimpleMatch wagen |
        ForEach-Object { $obj.psobject.Properties.Value -join ', ' }

Volkswagen, Passat

The Write-Output command is just a stand-in for the actual command that produces the input objects for Select-String in your code, such as Import-Csv.


  • Your Select-String output implies that [pscustomobject] instances served as its input, such as output by Import-Csv, for instance.

    • E.g., your output implies an input object such as
      [pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }
  • As Theo notes, Select-String is designed to operate on strings, not on objects with properties.

    • When Select-String receives such objects, it creates a string representation for them and searches that.

    • What makes this particularly unhelpful is that this string representation is not the same you would see in the terminal (console), where PowerShell's rich output formatting is used; instead, simple .ToString() stringification is performed, which with [pscustomobject] instances results in representations such as '@{Brand=Volkswagen; Model=Passat}' (perhaps confusingly, this resembles - but is not the same as - a hashtable literal).

      • GitHub issue #10726 proposes changing Select-String to instead operate on the rich display-formatting representations.
  • Additionally, if you do let Select-String operate on such objects, its output (Microsoft.PowerShell.Commands.MatchInfo instances) no longer contain the input objects, only their string representations, which means that in order to extract the values Volkswagen and Passat, you'd have to perform string parsing, which is both cumbersome and not robust.


To filter input objects with properties based on property values, Where-Object is the better choice; e.g.:

PS> [pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }, 
    [pscustomobject] @{ Brand = 'Ford'; Model = 'Mondeo' } |
      Where-Object Brand -eq Volkswagen

Brand      Model
-----      -----
Volkswagen Passat

That said, using Select-Object can still be helpful if you don't know what properties the input objects have, and want to locate a value somewhere in the object, via its string representation:

PS> [pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }, 
    [pscustomobject] @{ Brand = 'Ford'; Model = 'Mondeo' } |
      Select-String -SimpleMatch wagen

@{Brand=Volkswagen; Model=Passat}

The above is what you tried, but, as stated, this effectively outputs just the string representation of the entire object, with no (easy) ability to extract property values afterwards.

The solution is to use the common -PipelineVariable parameter on the input-object-producing command, which allows access to the object at hand in a later pipeline segment's (ForEach-Object) script block, which allows you to create the desired comma-separated list of property values easily (even without knowing the property names):

# Note the use of -PipelineVariable obj and the use of $obj later.
PS> Write-Output -PipelineVariable obj (
      [pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }, 
      [pscustomobject] @{ Brand = 'Ford'; Model = 'Mondeo' }
    ) |
      Select-String -SimpleMatch wagen |
        ForEach-Object { $obj.psobject.Properties.Value -join ', ' }

Volkswagen, Passat

$obj.psobject.Properties.Value uses the hidden, intrinsic .psobject property that PowerShell provides for all objects, which is a rich source of reflection and in this case allows easy access to all property values, via member-access enumeration.

mklement0
  • 382,024
  • 64
  • 607
  • 775