Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell Select-Object vs ForEach on Select-String results

Let's say I have the results of a call to Select-String in a variable $mat, parsing a regular expression from file contents:

$mat = cat errors.txt | Select-String "'(?<code>\w+)'.+ID (?<id>[^:]+)" 

According to the output of $mat | Get-Member the result contains a Matches property of type Match[].

When I execute the following I get all the matches of my regular expression output:

PS > $mat | Select-Object -Property Matches

Matches                                                                                                                                                                              
-------                                                                                                                                                                              
{'ACCFWD', ID 16}                                                                                                                                                                    
{'EQASIAN', ID 448}                   
    

Why doesn't this next block of code using foreach to select the Matches have the same output:

    PS > $mat | ForEach { $_.Matches } 


Groups   : {'ACCFWD', ID 16, ACCFWD, 16}
Success  : True
Captures : {'ACCFWD', ID 16}
Index    : 20
Length   : 15
Value    : 'ACCFWD', ID 16

Groups   : {'EQASIAN', ID 448, EQASIAN, 448}
Success  : True
Captures : {'EQASIAN', ID 448}
Index    : 20
Length   : 17
Value    : 'EQASIAN', ID 448
like image 866
Mikeyg36 Avatar asked Sep 09 '11 14:09

Mikeyg36


Video Answer


2 Answers

When displaying properties, PowerShell auto-formats the properties of types that do not have a display format defined in a *.format.ps1xml file as a table for up to 4 properties. 5 or more properties displays as a list. When you select the Matches property with Select-Object, you are selecting a single property of the Microsoft.PowerShell.Commands.MatchInfo object. With Foreach-Object you are displaying all of the properties for a System.Text.RegularExpressions.Match object.

Using Select-Object -ExpandProperty Matches will cause the output to look the same as the Foreach because it will output RegularExpressions.Match objects.

If you place Get-Member after both of your examples that produce output you will see that they output different types of objects.

Edit: Here is an explanation of the formatting that happens for each command.

cat errors.txt | Select-String "'(?<code>\w+)'.+ID (?<id>[^:]+)"

The output of Select-String is a Microsoft.PowerShell.Commands.MatchInfo object which has 8 properties. These properties are not displayed by default because the display format for MatchInfo is defined in PowerShellCore.format.ps1xml to show the result of MatchInfo's ToString() method.

$mat | Select-Object -Property Matches

In this case, the output of Select-Object is a custom Selected.Microsoft.PowerShell.Commands.MatchInfo object with the Matches property that was copied from the MatchInfo object. Since there is no default display format defined for the Selected.Microsoft.PowerShell.Commands.MatchInfo type, PowerShell auto formats it as a table since it has less than 5 properties (In this case Matches is the only property).

$mat | ForEach { $_.Matches } 

In the Foreach-Object ScriptBlock, the Matches property of the MatchInfo object is being output. The Matches property is a System.Text.RegularExpressions.Match which has 6 properties. Since there is no default display format defined for the System.Text.RegularExpressions.Match type, the Match objects are displayed as a list because there are more than 4 properties.

like image 144
Rynant Avatar answered Oct 03 '22 17:10

Rynant


If you use -ExpandProperty instead of -Property, then the two outputs will be the same.

$mat | Select-Object -ExpandProperty Matches

That works for this particular example, but for accessing a single property, Select-Object -ExpandProperty is still not exactly the same as ForEach in all cases. I would use ForEach. Also, see this example: http://community.idera.com/powershell/powertips/b/tips/posts/use-foreach-object-instead-of-select-object-expandproperty

like image 22
Jamey Avatar answered Oct 03 '22 17:10

Jamey