Reputation: 2304
Can anyone explain this strange powershell behavior.
If I declare the following:
$MyCollection = New-Object System.Collections.ArrayList
$MyCollection.Add(@{'Val1'=1; 'Val2'=2; 'Val3'=3})
$MyCollection.Add(@{'Val1'=1; 'Val2'=2; 'Val3'=3})
$MyCollection.Add(@{'Val1'=1; 'Val2'=2; 'Val3'=3})
So... I should have an object that looks like this:
System.Collections.Array.List
Index Item
0 {System.Collections.HashTable}
1 {System.Collections.HashTable}
2 {System.Collections.HashTable}
However if I get member you'll see my entire colleciton has become one large hash table
$MyCollection | Get-Member
TypeName: System.Collections.Hashtable
Name MemberType Definition
---- ---------- ----------
Add Method void Add(System.Object key, System.Object value), void IDictionary.Add(System.Object key, System.Object value)
Clear Method void Clear(), void IDictionary.Clear()
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
Contains Method bool Contains(System.Object key), bool IDictionary.Contains(System.Object key)
ContainsKey Method bool ContainsKey(System.Object key)
ContainsValue Method bool ContainsValue(System.Object value)
CopyTo Method void CopyTo(array array, int arrayIndex), void ICollection.CopyTo(array array, int index)
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IDictionaryEnumerator GetEnumerator(), System.Collections.IDictionaryEnumerator IDictionary.GetEnumerator(), System.Collections.IEnumerator IEnumerable.GetEn...
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context), void ISerializable.GetObjectData(System.Runtime....
GetType Method type GetType()
OnDeserialization Method void OnDeserialization(System.Object sender), void IDeserializationCallback.OnDeserialization(System.Object sender)
Remove Method void Remove(System.Object key), void IDictionary.Remove(System.Object key)
ToString Method string ToString()
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
And the behavior is like this. For instance I can't access my object the way I want to:
$MyCollection | %{$_.Val1}
outputs
1
1
1
Expected output
1
As you can see we have one large hash table now with very strange behavior. Can anyone explain what Powershell is actually doing? Because it is defiantly not accessing a HashTable inside an ArrayList collection.
its like calling any cmdlets flattens my data structure into a single hash table
Upvotes: 2
Views: 3652
Reputation: 1562
When you pass an array via the pipeline it is unrolled so in your example Get-Member
is seeing the internals of the array, the hashtables.
To get the type of an object that is an array you can use the GetType()
method and look to the name property.
$MyCollection.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ArrayList System.Object
Ansgar Wiechers showed below that you can also use the -InputObject
parameter to get the type of an array.
Get-Member -InputObject $MyCollection
If you want only a single item from the array of hashtables output you'll need to specify which index in the array you want the value followed by the hashtable key.
$MyCollection[0]['Val1']
1
The example above returns the value stored in the key Val1
of the first object in the array. To get the others you'll have to increment the index number or change the key.
Upvotes: 4