Search code examples
arrayspowershellselect-string

How to display values from a powershell array created by select-string


I have an array and use select-string to find duplicates.

$2 = $arraySNOW | Select-String -Pattern $request

The process usually finds 2 items and but each item is now rapped inside @{} object and I can not access the value for a specific property

$2[0]

@{number=63887630; request=abc560vi}

$2 | Get-Member
TypeName: Microsoft.PowerShell.Commands.MatchInfo

$2.gettype()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

How to pull the value of the request for both items in $2?


Solution

  • Santiago Squarzon has provided the crucial pointer:

    Select-String is for string searches, whereas you want OO techniques to filter your objects, so you should use Where-Object to filter your objects by a property value of interest:

    # Filters the input objects by whether their .Request property
    # matches the specified regex pattern.
    $arraySNOW | Where-Object Request -match $request
    

    The above passes the matching input objects through, so you can access their properties as needed; e.g., to get the .number property values of the matching objects:

    $arraySNOW | Where-Object request -match $request |
      ForEach-Object number  # alternatively: Select-Object -ExpandProperty number
    

    Or, more succinctly, using member-access enumeration:

    ($arraySNOW | Where-Object request -match $request).number
    

    As for what you tried:

    $arraySNOW | Select-String -Pattern $request returns any number of Microsoft.PowerShell.Commands.MatchInfo instances describing the string matches performed on the input objects.

    • Their .Line property contains the text of the input line or stringified input object (see below) that was matched; in PowerShell (Core) 7+, you can obtain this text directly with the -Raw switch.

    If Select-Object emits two ore more objects and you capture them in a variables ($2 = ...) PowerShell automatically collects them in an [object[]] (System.Object[]) array for you.

    • Piping an array (a list-like enumerable) to Get-Member invariably results in the array's enumeration, so that Get-Member reports the distinct types among its elements - hence the report of type Microsoft.PowerShell.Commands.MatchInfo

    • By contrast, calling .GetType() on any object - whether it is a scalar or an array / list / collection - reports its own type.

    The for-display representation of a MatchInfo instance you saw with $2[0] is in essence the value of its .Line property:

    • Non-string input to Select-Object is implicitly stringified, and the stringified value is both used for matching and reported via the .Line property.

    • Therefore, you lose the object identity of the input, and simply get a string representation of it.

      • The specific form of the string representation you saw - @{number=63887630; request=abc560vi} resembles PowerShell hashtable literals - but is, in fact, how [pscustomobject] instances are stringified - see this answer for details.

      • With many other types, the implicit stringification results in useless representations, namely simply the full type name of the input object, given that .ToString() stringification (with some custom functionality overlaid) is applied (e.g., stringifying a hashtable results in string 'System.Collections.Hashtable'; try @{ foo = 1 }.ToString())

      • Given that PowerShell has a rich for-display output-formatting system that provides much more helpful representations of most types, it is unfortunate that Select-String doesn't apply PowerShell's formatting implicitly; see GitHub issue #10726 for a discussion.