3

I am exploring what pipeline functionality is also available as methods. For example... @('1', '2', '3', '2') | where {$_ -in @('2')} will return the two '2'. But I can also do... @('1', '2', '3', '2').Where({$_ -in @('2')}) and get the same result.

I also want to Group, and while @('1', '2', '3', '2') | group {$_.Count -gt 1} doesn't do the actual grouping I want, it does... something. But @('1', '2', '3', '2').Group({$_.Count -gt 1}) fails with Method invocation failed because [System.String] does not contain a method named 'Group'.

So that got me looking for what IS available as intrinsic methods. @('1') | Get-Member -MemberType Method -Force | Format-Table doesn't even include Where and yet the Method is there. So I assume it is inheriting that method. But I don't know how to include inherited Methods. I though -Force would do it but it doesn't, nor does -View provide any more detail.

Is there a way to explore these intrinsic methods such as .Where()? And perhaps tangentially, is there a way to Group as a method rather than with the pipeline?

Gordon
  • 6,257
  • 6
  • 36
  • 89

2 Answers2

2

Dabombber's answer is helpful, but let me try to give a systematic overview:

The .Where() and .ForEach() array methods are instances of what are known as intrinsic members; no other such intrinsic array-processing (collection-processing) methods exist as of PowerShell 7.1

Intrinsic members are members (properties and methods) that the PowerShell engine exposes on objects of any type - except if the object has a native .NET type member of the same name, which takes precedence.

Discovery limitations, as of PowerShell 7.1 / late 2020:

  • Intrinsic members cannot be discovered via Get-Member

  • Tab completion works only for .Where() and .ForEach() (on collection values), but not for other intrinsic members, such as the .psobject property (see below).

  • However, they are documented in the conceptual about_Intrinsic_Members help topic.

In short: as of this writing, you cannot discover intrinsic members programmatically.


List of intrinsic members:

  • Intrinsic members that enable unified treatment of collections (arrays) and scalars:

    • PowerShell adds .Count and .Length properties (aliases of each other) even to scalars (assuming they don't have type-native properties of the same name), with an non-null scalar sensibly reporting 1 (e.g., (42).Count), and $null reporting 0 ($null.Count)

      • Pitfalls:
        • Accessing these properties while Set-StrictMode -Version 2 or higher is in effect unexpectedly causes statement-terminating errors, because the engine treats them as non-existent; this long-standing bug is discussed in GitHub issue #2798.

        • IEnumerable instances such as returned by LINQ methods aren't collections per se, and calling .Count on them triggers enumeration and returns a .Count property value from each enumerated element instead (which defaults to 1); e.g., [Linq.Enumerable]::Range(1,3).Count returns array 1, 1, 1 instead of 3.

        • There is a bug in Windows PowerShell (as of the latest and final version, 5.1), which has since been corrected in PowerShell (Core): [pscustomobject] instances unexpectedly do not have .Count and .Length properties (see GitHub issue #3671 for the original bug report) - see this answer.

    • Similarly, PowerShell allows you to index even into a scalar (again, unless preempted by a type-native indexer, such as that of XmlElement); e.g., (42)[0] and (42)[-1] both return 42, i.e. the scalar itself.

  • Collection-processing intrinsic members:

    • These are (only) the .Where() and .ForEach() methods discussed above.

    • Note that, in the the interest of unified treatment of collections and scalars, these methods also work on scalars; e.g., (42).ForEach({ $_ + 1 }) yields 43.

    • Pitfalls:

      • In Windows PowerShell (since fixed in PowerShell [Core] 7+), some types of scalars - notably [pscustomobject] and [xml] - do not provide these methods, which should be considered a bug.

      • The System.Collections.Generic.List<T> collection type has its own .ForEach() method that therefore shadows PowerShell's; this type-native method neither supports the use of $_ nor producing output.

  • Intrinsic members for reflection (not available on $null):

    • The .psobject property is a rich source of reflection on any object, such as its list of properties; e.g., (Get-Date).psobject.Properties lists metadata about all public properties of instances of System.DateTime.

    • .pstypenames (also available as .psobject.TypeNames) lists all ETS (Extended Type System) type names associated with an instance; by default, the property contains the full names of the object's .NET type and its base type(s).

    • The .psbase, .psextended, and .psadapted properties return categorized subsets of type members, namely .NET-native, ETS-added, and adapted members.

      • Adapted members are members that surface information from a different data representation as if they were native type members, notably in the context of CIM (WMI) and PowerShell's adaptation of the XML DOM.

      • For instance, [xml] (System.Xml.XmlDocument) instances have members in all three categories; try $xml = ([xml] '<someElement>some text</someElement>'); '-- .psbase:'; $xml.psbase; '-- .psextended'; $xml.psextended; '-- .psadapted'; $xml.psadapted

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

Your arrays are getting unrolled through the pipeline, so @('1') | Get-Member -MemberType Method -Force is showing members for a string.

You can bypass that by sending it as the second object of an array

,@('1') | Get-Member -MemberType Method

outputting it without enumeration

Write-Output -NoEnumerate @('1') | Get-Member -MemberType Method

or passing it as a parameter instead of through the pipeline.

Get-Member -InputObject @('1') -MemberType Method

Some of the methods may also be static, so you could use the -Static switch for Get-Member.

There is a list of array methods here, although I have no idea why not all of them show up, perhaps it's an intentional part of the Get-Member cmdlet or maybe they're part of the PowerShell language itself rather than proper methods.

Dabombber
  • 436
  • 3
  • 8
  • Ugh, gotta remember that goofy single element array unroll behavior! Though in this case that still doesn't expose the `.Where()` method. Though that link does answer the question "Is there a Group method?" Nope. :( – Gordon Dec 26 '20 at 12:39
  • Yea, I'm aware I don't really answer your main question (luckily mklement0 does), but it's a little too much for a comment. As for grouping, if it's purely for display purposes, you may want to play with the `GroupBy` element of [formatting files](https://learn.microsoft.com/powershell/scripting/developer/format/list-view-groupby). – Dabombber Dec 27 '20 at 02:24