November 1st, 2015

Weekend Scripter: Exploring PowerShell Arrays

Doctor Scripto
Scripter

Summary: Ed Wilson, Microsoft Scripting Guy, talks about Exploring Windows PowerShell arrays.

Microsoft Scripting Guy, Ed Wilson, is here. One of the problems I had with Windows PowerShell when I first learned it was handling arrays. Why? Because they were so easy. Well, they are easy, but they are also a bit confusing. Why? Because Get-Member seems to hide the type, so I may have an array, and it will report string. But that is something I will talk about in a minute. First, let's look at creating an array.

Create an array in PowerShell

The easiest way to create an array is to simply create a variable and assign more than one item to it. Here is an example:

$a = 1,2,3,4,5

As shown here, if I pipe the $a variable to the Get-Member (gm is an alias) cmdlet, it reports that it is a System.Int32:

PS C:\> $a | gm

   TypeName: System.Int32

Name        MemberType Definition

—-        ———- ———-

CompareTo   Method     int CompareTo(System.Object value), int CompareTo(int valu…

Equals      Method     bool Equals(System.Object obj), bool Equals(int obj), bool…

GetHashCode Method     int GetHashCode()

GetType     Method     type GetType()

GetTypeCode Method     System.TypeCode GetTypeCode(), System.TypeCode IConvertibl…

ToBoolean   Method     bool IConvertible.ToBoolean(System.IFormatProvider provider)

ToByte      Method     byte IConvertible.ToByte(System.IFormatProvider provider)

ToChar      Method     char IConvertible.ToChar(System.IFormatProvider provider)

ToDateTime  Method     datetime IConvertible.ToDateTime(System.IFormatProvider pr…

ToDecimal   Method     decimal IConvertible.ToDecimal(System.IFormatProvider prov…

ToDouble    Method     double IConvertible.ToDouble(System.IFormatProvider provider)

ToInt16     Method     int16 IConvertible.ToInt16(System.IFormatProvider provider)

ToInt32     Method     int IConvertible.ToInt32(System.IFormatProvider provider)

ToInt64     Method     long IConvertible.ToInt64(System.IFormatProvider provider)

ToSByte     Method     sbyte IConvertible.ToSByte(System.IFormatProvider provider)

ToSingle    Method     float IConvertible.ToSingle(System.IFormatProvider provider)

ToString    Method     string ToString(), string ToString(string format), string …

ToType      Method     System.Object IConvertible.ToType(type conversionType, Sys…

ToUInt16    Method     uint16 IConvertible.ToUInt16(System.IFormatProvider provider)

ToUInt32    Method     uint32 IConvertible.ToUInt32(System.IFormatProvider provider)

ToUInt64    Method     uint64 IConvertible.ToUInt64(System.IFormatProvider provider)

But if I use $a as an input object to Get-Member, it reports system.object[]. The [] means an array. This is shown here:

Image of command output

It is also interesting to look at the .psbase property. This is basically a hidden property, meaning that it does not readily appear and Tab expansion does not seem to show it. It is pretty cool. As shown here, it tells me the length, the rank, and other stuff.

PS C:\> $a.psbase

Length         : 5

LongLength     : 5

Rank           : 1

SyncRoot       : {1, 2, 3, 4…}

IsReadOnly     : False

IsFixedSize    : True

IsSynchronized : False

Count          : 5

Also cool is the PSObject property. Note especially, that at the bottom of the output, it says we have three types—one of which is System.Array:

PS C:\> $a.psobject

Members             : {Count = Length, int Length {get;}, long LongLength {get;},

                      int Rank {get;}…}

Properties          : {Count = Length, int Length {get;}, long LongLength {get;},

                      int Rank {get;}…}

Methods             : {void Set(int , System.Object ), System.Object&, mscorlib,

                      Version=4.0.0.0, Culture=neutral,

                      PublicKeyToken=b77a5c561934e089 Address(int ), System.Object

                      Get(int ), System.Object GetValue(Params int[] indices),

                      System.Object GetValue(int index), System.Object GetValue(int

                      index1, int index2), System.Object GetValue(int index1, int

                      index2, int index3), System.Object GetValue(long index),

                      System.Object GetValue(long index1, long index2),

                      System.Object GetValue(long index1, long index2, long

                      index3), System.Object GetValue(Params long[] indices)…}

ImmediateBaseObject : {1, 2, 3, 4…}

BaseObject          : {1, 2, 3, 4…}

TypeNames           : {System.Object[], System.Array, System.Object}

If I use the GetType() method that is automatically created, it tells me that I have an object[] (note the square brackets again) and that my BaseType is an array:

PS C:\> $a.GetType()

IsPublic IsSerial Name                           BaseType

——– ——– —-                                     ——–

True     True     Object[]                       System.Array

Use the range operator to save typing

One of my absolutely positively favorite operators is the range operator. It is simply a couple of dots. It will create an array with the numbers in the range. The reason it is so cool is that I can easily create an array with 2 or with 2,000,000 elements in it. It really doesn’t matter. Here is an example:

PS C:\> $b = 1..2000000

PS C:\> $b.Count

2000000

Is it an array? Well, when I use GetType(), it says, yep, it is an array:

PS C:\> $b.GetType()

IsPublic IsSerial Name                           BaseType

——– ——– —-                                     ——–

True     True     Object[]                        System.Array

Create a strongly typed array

One of the things that is way cool about Windows PowerShell is that it is a strongly typed language, but it behaves as if it were typeless. What this means is that everything is an object, and every object is a type of something. For instance, in the previous array, the type was System.Array, but the array held. An int32 holds numbers from -2147483648 to 2147483647 in size. This is shown here:

PS C:\> [int32]::MaxValue

2147483647

PS C:\> [int32]::MinValue

-2147483648

int32 is the default. But what if I don’t need a number that big? Well, I can change to int16. As you can see here, int16 has a maximum value of 32767:

PS C:\> [int16]

IsPublic IsSerial Name                           BaseType

——– ——– —-                                     ——–

True     True     Int16                            System.ValueType

PS C:\> [int16]::MaxValue

32767

If I want to ensure that my array does not change, I can use [int16[]] to constrain the type or to keep it from changing. If I try to assign a number that is too large, it generates the following error message:

Image of message

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.