Search
Joe Pruitt - A Software Architect's take on Network Security
You are here: DevCentral > Weblogs

posted on Wednesday, January 21, 2009 9:15 AM

PowerShell Welcome to this addition of the PowerShell ABC's where you'll find 26 posts detailing a component of the PowerShell scripting language, one letter at a time.  For today's letter of "U" I will talk about PowerShell's automatic unraveling of collections.

To unravel is to "separate or disentangle the threads" or "to free from complication or difficulty; make plain or clear".

unravel_baseball One problem that people run into with .NET methods that return enumerators is that PowerShell will unravel the enumerator by default.  By this I mean that it will "take it apart" and put it in a format that is more understandable to the user.

The foreach statement can be used to iterate over enumerable objects which typically includes anything that implements the .NET IEnumerable interface.  But, PowerShell is not strict on that.  There are some classes that PowerShell does not consider enumerable such as strings, dictionaries, or hashtables.  The reason for this is obvious after you think of it.  Consider a string for instance.  In most cases, you wouldn't want all strings to suddenly be converted into a stream of characters.  Or for a hash table, you wouldn't likely want that to be auto-converted into a sequence of key/value pairs.  In most cases you would want these types to be treated as lightweight scalar objects.

Now, that's not saying that you can't get coerce PowerShell into treating those types as enumerators.  The GetEnumerator() method can be used to extract the IEnumerable interface on an object and allow you to iterate through it's pieces. 

PS C:\> foreach ($c in "abc") { $c }
abc
PS C:\> foreach ($c in "abc".GetEnumerator()) { $c }
a
b
c

But automatic unraveling can be useful when you are iterating over collections.  Consider the following example:

PS C:\> foreach ($c in ("a","b","c")) { $c }
a
b
c
PS C:\> foreach ($c in ("a","b","c").GetEnumerator()) { $c }
a
b
c

This may be a bit counter-intuitive for .NET programmers as common practice is to use the Open() method to get an enumerator, process the enumerator, and then call the Close() method.  PowerShell will see the enumerator returned from the Open() method and process it immediately.

Automatic unraveling can also be confusing in the context of returning an object from a function call.  If you would like to return an enumerable object from a function or script, you'll want to wrap that object in an array using the unary comma operator.

PS C:\> return 1,2,3,4 | Get-Member 

   TypeName: System.Int32

Name        MemberType Definition
----        ---------- ----------
CompareTo   Method     System.Int32 CompareTo(Int32 value), System.Int32 CompareTo(Object value)
Equals      Method     System.Boolean Equals(Object obj), System.Boolean Equals(Int32 obj)
GetHashCode Method     System.Int32 GetHashCode()
GetType     Method     System.Type GetType()
GetTypeCode Method     System.TypeCode GetTypeCode()
ToString    Method     System.String ToString(), System.String ToString(IFormatProvider provider),...

PS C:\> return ,(1,2,3,4) | Get-Member

   TypeName: System.Object[]

Name           MemberType    Definition
----           ----------    ----------
Count          AliasProperty Count = Length
Address        Method        System.Object& Address(Int32 )
Clone          Method        System.Object Clone()
CopyTo         Method        System.Void CopyTo(Array array, Int32 index), System.Void CopyTo(Array array, Int64 index)
Equals         Method        System.Boolean Equals(Object obj)
Get            Method        System.Object Get(Int32 )
GetEnumerator  Method        System.Collections.IEnumerator GetEnumerator()
GetHashCode    Method        System.Int32 GetHashCode()
GetLength      Method        System.Int32 GetLength(Int32 dimension)
GetLongLength  Method        System.Int64 GetLongLength(Int32 dimension)
GetLowerBound  Method        System.Int32 GetLowerBound(Int32 dimension)
GetType        Method        System.Type GetType()
GetUpperBound  Method        System.Int32 GetUpperBound(Int32 dimension)
GetValue       Method        System.Object GetValue(Params Int32[] indices), System.Object GetValue(Int32 index), Sy...
Initialize     Method        System.Void Initialize()
Set            Method        System.Void Set(Int32 , Object )
SetValue       Method        System.Void SetValue(Object value, Int32 index), System.Void SetValue(Object value, Int...
ToString       Method        System.String ToString()
IsFixedSize    Property      System.Boolean IsFixedSize {get;}
IsReadOnly     Property      System.Boolean IsReadOnly {get;}
IsSynchronized Property      System.Boolean IsSynchronized {get;}
Length         Property      System.Int32 Length {get;}
LongLength     Property      System.Int64 LongLength {get;}
Rank           Property      System.Int32 Rank {get;}
SyncRoot       Property      System.Object SyncRoot {get;}



Feedback

No comments posted yet.

Let Me Know What You Think


Please use the form below if you have any comments, questions, or suggestions.

Title:
 
Name:
 
Email: (so we can show your gravatar)
Website:
Comment: Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code
 
Please add 4 and 7 and type the answer here:

Blog Stats

Posts:379
Comments:1067
Stories:1
Trackbacks:301
  

Article Categories

  iRules
  

Image Galleries

  

Joe's bookshelf: read

The Lost Gate
4 of 5 stars
This one started slow but I got really got into it about 1/3 of the way through. If you are an Ender's Game fan, you'll probably like this one as well.

goodreads.com


82,243 Members in 102 Countries and Growing!

Join DevCentral Today!

About DevCentral

DevCentral has been a successful, thriving community for many years. We have always strived to bring you the best technical documentation, discussion forums, blogs, media and much more that we can.

So dive in, get familiar with DevCentral. We hope you like it, we hope it makes your job easier, and lets you get that much more power out of the community. To learn more, make sure to check out the Getting Started section. And if you have any problems, or think something could be easier to use, drop us a line to let us know.

Got It !

We've received your comment and transmitted it directly to DevCentral HQ.

Thanks for taking time to let us know what's on your mind. At DevCentral | Community Matters!

Get In Touch With Us

Have questions, suggestions or just want to get something off your chest?

Use our handy form below to Direct Connect with DevCentral Mission Control.

Send Us Feedback       or