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
1IgnoreCase : 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 : {}}
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 2may be somthing lie this :
Select-String -Path "C:\temp\test.txt" -Pattern "test" | select line -ExpandProperty line 1To 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-Stringoutput implies that[pscustomobject]instances served as its input, such as output byImport-Csv, for instance.- E.g., your output implies an input object such as
[pscustomobject] @{ Brand = 'Volkswagen'; Model = 'Passat' }
- E.g., your output implies an input object such as
As Theo notes,
Select-Stringis designed to operate on strings, not on objects with properties.When
Select-Stringreceives 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-Stringto instead operate on the rich display-formatting representations.
- GitHub issue #10726 proposes changing
Additionally, if you do let
Select-Stringoperate on such objects, its output (Microsoft.PowerShell.Commands.MatchInfoinstances) no longer contain the input objects, only their string representations, which means that in order to extract the valuesVolkswagenandPassat, 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.