1

Properties not appearing in the Get-Member cmdlet and registering values when put in . notation

Running
Get-ChildItem | Get-member
TypeName: System.IO.DirectoryInfo

Name                      MemberType     Definition
----                      ----------     ----------
LinkType                  CodeProperty   System.String LinkType{get=GetLinkType;}
Mode                      CodeProperty   System.String Mode{get=Mode;}….

There is no Count property, for the GCI cmdlet there is a count property for the Measure-object cmdlet, as seen.

PS C:\Users\NiceTry5> measure-object | get-member




TypeName: Microsoft.PowerShell.Commands.GenericMeasureInfo

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
ToString    Method     string ToString()
Average     Property   System.Nullable[double] Average {get;set;}
Count       Property   int Count {get;set;}

Why then does the count property of the measure-object cmdlet register a value for the GCI cmdlet?

PS C:\Users\NiceTry5> (GCI).count
32

I believe the count property must belong to some sort of superset that contains the GCI cmdlet, and is hidden when running Get-member, although I'm not sure.

1 Answers1

2
  • Get-Member operates on the individual objects received via the pipeline and returns information about the distinct types among them.

    • Therefore, with the output from a Get-ChildItem command targeting the file-system, you'll see information about types System.IO.DirectoryInfo and/or System.IO.FileInfo - and these types have no .Count property.

    • In order to inspect a collection-like type itself (rather than its elements), pass it to
      Get-Member's -InputObject parameter instead of using the pipeline; e.g,
      Get-Member -InputObject (Get-ChildItem).

  • (...) around a command that outputs multiple objects implicitly collects these objects in an [object[]] array, and any array has a .Count property, by virtue of the IList interface it implements.

    • That said, PowerShell (since v3) implicitly provides a .Count property even on scalars, in an effort to unify the handling of scalars and collections; e.g., (Get-Date).Count yields 1, as do 'foo'.Count and (42).Count (sic) - however,
      Get-Member does not show this implicit .Count property.

      • You can even use indexing ([...]) with scalars so as to treat them as a single-element array; e.g., (42)[0] is the same as 42 - see this answer for more information (a notable exception is [string], because that type itself defines indexing as accessing the individual characters in the string; e.g, 'foo'[0] is 'f')

      • Such implicitly available members - which aren't native to the .NET type at hand - are calle intrinsic members.


Notable pitfalls :

  • Using the implicit .Count property fails when Set-StrictMode -Version 2 or higher is in effect:

    • e.g., Set-StrictMode -Version 2; (42).Count fails with The property 'Count' cannot be found on this object.

    • This problematic behavior is discussed in this GitHub issue.

  • In Windows PowerShell (whose latest and final version is 5.1), [pscustomobject] instances do not have a .Count property, due to a bug, as detailed in this answer - this has been corrected in PowerShell (Core, v6+).

  • A collection-like type that doesn't itself have a .Count property, e.g. a lazy enumerable, results in .Count being called on each individual element, due to member-access enumeration:

    • e.g.,[System.IO.Directory]::EnumerateFiles('.').Count - because EnumerateFiles() returns a lazily enumerated [System.Collections.Generic.IEnumerable[string]] instance that therefore cannot have a .Count property - calls .Count on each path that is enumerated, resulting in an array of 1s, because each individual path - as a scalar - has a count of 1.
mklement0
  • 382,024
  • 64
  • 607
  • 775