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?

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

Comments

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.

2 Comments

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. :(
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.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.