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?
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:

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...
...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With