1

Suppose $coll is a collection of objects. $coll | Get-Member displays the members of a collection item. I do not know how it works exactly, whether it inspects the first item and stops or it shows the union of members of all the items. Nevertheless, it inspects the items, not the collection object itself. Which is usually, what we want.

But what if I want to inspect the collection itself? Can I still do it or must I use the .NET reflection functions?

mark
  • 59,016
  • 79
  • 296
  • 580

2 Answers2

2

Stupid me, of course it can. I just have to use the -InputObject parameter, instead of pipeline - Get-Member -InputObject $coll instead of $coll | Get-Member

C:\WINDOWS\System32> $x = @([pscustomobject]@{a = 1})
C:\WINDOWS\System32> $x|Get-Member


   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
a           NoteProperty int a=1


C:\WINDOWS\System32> Get-Member -InputObject $x


   TypeName: System.Object[]

Name           MemberType            Definition
----           ----------            ----------
Count          AliasProperty         Count = Length
Add            Method                int IList.Add(System.Object value)
Address        Method                System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a...
Clear          Method                void IList.Clear()
Clone          Method                System.Object Clone(), System.Object ICloneable.Clone()
CompareTo      Method                int IStructuralComparable.CompareTo(System.Object other, System.Collections.ICo...
Contains       Method                bool IList.Contains(System.Object value)
CopyTo         Method                void CopyTo(array array, int index), void CopyTo(array array, long index), void...
Equals         Method                bool Equals(System.Object obj), bool IStructuralEquatable.Equals(System.Object ...
Get            Method                System.Object Get(int )
GetEnumerator  Method                System.Collections.IEnumerator GetEnumerator(), System.Collections.IEnumerator ...
GetHashCode    Method                int GetHashCode(), int IStructuralEquatable.GetHashCode(System.Collections.IEqu...
GetLength      Method                int GetLength(int dimension)
GetLongLength  Method                long GetLongLength(int dimension)
GetLowerBound  Method                int GetLowerBound(int dimension)
GetType        Method                type GetType()
GetUpperBound  Method                int GetUpperBound(int dimension)
GetValue       Method                System.Object GetValue(Params int[] indices), System.Object GetValue(int index)...
IndexOf        Method                int IList.IndexOf(System.Object value)
Initialize     Method                void Initialize()
Insert         Method                void IList.Insert(int index, System.Object value)
Remove         Method                void IList.Remove(System.Object value)
RemoveAt       Method                void IList.RemoveAt(int index)
Set            Method                void Set(int , System.Object )
SetValue       Method                void SetValue(System.Object value, int index), void SetValue(System.Object valu...
ToString       Method                string ToString()
Item           ParameterizedProperty System.Object IList.Item(int index) {get;set;}
IsFixedSize    Property              bool IsFixedSize {get;}
IsReadOnly     Property              bool IsReadOnly {get;}
IsSynchronized Property              bool IsSynchronized {get;}
Length         Property              int Length {get;}
LongLength     Property              long LongLength {get;}
Rank           Property              int Rank {get;}
SyncRoot       Property              System.Object SyncRoot {get;}


C:\WINDOWS\System32>
mark
  • 59,016
  • 79
  • 296
  • 580
  • Yes, that's one of the rare cases where the differing behavior between _implicilty_ binding `-InputObject` _via the pipeline_ and doing so _explicitly_, via an _argument_ is meaningful and useful; more typically, it isn't - see [this GitHub issue](https://github.com/PowerShell/PowerShell/issues/4242). – mklement0 Nov 03 '19 at 03:54
  • Does not seem it will ever be fixed. – mark Nov 03 '19 at 20:13
  • You can also wrap ```$x``` in a "sacrificial array" so the pipeline passes ```$x``` into ```Get-Member``` rather than ```$x[...]``` - e.g. ```@(,$x) | get-member``` – mclayton Nov 04 '19 at 11:09
1

According to the documentation for the parameters to Get-Member:

-InputObject

Specifies the object whose members are retrieved.

Using the InputObject parameter is not the same as piping an object to Get-Member. The differences are as follows:

When you pipe a collection of objects to Get-Member, Get-Member gets the members of the individual objects in the collection, such as the properties of each string in an array of strings.

When you use InputObject to submit a collection of objects, Get-Member gets the members of the collection, such as the properties of the array in an array of strings.

so $coll | Get-Member will invoke Get-Member on each item in the collection, but Get-Member -InputObject $coll will invoke Get-Member on the collection object itself.

However, if you're a fan of using the pipeline you can use a cheap trick to coerce PowerShell into doing the former with a collection object by wrapping it in a sacrificial array (name borrowed from this answer) containing a single element:

@( ,$coll ) | Get-Member

and PowerShell will happily unwrap the outer array and invoke Get-Member for each child item - in this case your original collection object.

mclayton
  • 8,025
  • 2
  • 21
  • 26