how to expand multiple properties when output contains @{, }?

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 : {}}

1

3 Answers

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 
2

may be somthing lie this :

Select-String -Path "C:\temp\test.txt" -Pattern "test" | select line -ExpandProperty line 
1

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.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like