Jamie Marshall
Jamie Marshall

Reputation: 2304

System.Collections.ArrayList becomes System.Collecitons.HashTable

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

Answers (1)

Persistent13
Persistent13

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

Related Questions