Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell understand Get-Member

Tags:

powershell

I'm having a problem understanding the "Get-Member" Definition column. I'm doing:

$Array = "ans", "zwei","drei"

$Array.GetType() gives back - as expected - BaseType=System.Array

Then:

$Array | gm 

says nothing about a method Add() - which is correct since $Array is an array.

But:

gm -inputobject $Array 

is showing me an Add()-Method, with the definition

int IList.Add(System.Object value).

Of course: $Array.Add("vier") doesn't work.
I know: IList is an interface etc. but it's here completely wrong since we're talking of a variable of an Array-type?

To make the chaos perfect: the intellisense of my ISE (PS Version: 4) is showing the Add()-Method as well.

What a mess. How to understand correctly the "definition" column using Get-Member?

like image 804
Purclot Avatar asked Sep 19 '26 04:09

Purclot


2 Answers

The type of this object:

$Array = "ans","zwei","drei"

if not System.Array, but Object[] - a type of collection that directly inherits from System.Array, but is not the same as.

If you dig a little deeper down the rabbithole, you'll find that the type of $Array does in fact implement IList:

PS C:\> $Array.GetType().ImplementedInterfaces
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    ICloneable
True     False    IList
True     False    ICollection
True     False    IEnumerable
True     False    IStructuralComparable
True     False    IStructuralEquatable
True     False    IList`1
True     False    ICollection`1
True     False    IEnumerable`1
True     False    IReadOnlyList`1
True     False    IReadOnlyCollection`1

The reason $Array | gm doesn't show an Add() method is that when you pipe $Array to gm, the pipeline tries to enumerate the contents of $Array, and what gm shows you is really the members of the contained type - a System.String:

enter image description here

To get the members of the array object itself instead of those of the array elements you must pass it to Get-Member via the -InputObject method:

PS C:\> Get-Member -InputObject $Array

   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, C...
Clear          Method                void IList.Clear()
Clone          Method                System.Object Clone(), System.Object IClonea...
CompareTo      Method                int IStructuralComparable.CompareTo(System.O...
Contains       Method                bool IList.Contains(System.Object value)
CopyTo         Method                void CopyTo(array array, int index), void Co...
Equals         Method                bool Equals(System.Object obj), bool IStruct...
...
like image 58
Mathias R. Jessen Avatar answered Sep 21 '26 18:09

Mathias R. Jessen


The trick is that $array | get-member returns a System.String as a type in this case, that string does not have a "Add" method. If your array would be equal to, say, @(1,2), you'll get an output of System.Int32 as "its" type. The reason on this is that you're using pipelines that are designed to unfurl arrays into cmdlets that normally are designed to perform one action per input member. So, the get-member -InputObject $array is the proper way of querying arrays for members, and not querying its members for their members.

The trick with $array.Add('vier') is a tad different - I've just tested and the exception does not say "illegal call", it says "size is fixed", and it is indeed so, $array.IsFixedSize returns true. The probable reason for this is to not expose the actual IList alteration mechanics and just declare them "fixed size" and only override this limit in operators or methods designed to accept arrays.

UPDATE: As @Mathias says in his answer, the actual type of $array is System.Object[] which I missed, and by the list of its interfaces, it was designed to declare itself as "read only" to .NET methods on interfaces, so it should only be modified by Powershell code, not .NET code.

like image 23
Vesper Avatar answered Sep 21 '26 17:09

Vesper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!