Variables as Objects


Earlier we mentioned that even variables are objects. In particular, string variables in .NET are extremely robust and have a number of methods and properties that you'll meet in Chapter 5. One of them is Split, which is a method that takes a string and creates an array (or list) out of it by breaking the list up on some character like a comma or a space. Try this in PowerShell:

 PS:> "1,2,3,4".Split(",") 

What you're telling PowerShell is "take this string and execute its Split method. Use a comma for the method's input argument." When PowerShell does this, the method returns an array of four elements that each contains a number. PowerShell gets that array and displays it in a textual fashion with one array element per line:

 1 2 3 4 

There are other ways to use this technique. For example, PowerShell has a cmdlet called Get-Member that displays the methods and variables associated with a given object instance. So, take a string like "Hello, World"-which, remember, is an instance of a String object-and pipe it to the Get-Member cmdlet to display information about that String object:

 PS C:\> "Hello, World" | get-member    TypeName: System.String Name             MemberType            Definition ----             ----------            ---------- Clone            Method                System.Object Clone() CompareTo        Method                System.Int32 CompareTo(Objec Contains         Method                System.Boolean Contains(Stri CopyTo           Method                System.Void CopyTo(Int32 sou EndsWith         Method                System.Boolean EndsWith(Stri Equals           Method                System.Boolean Equals(Object get_Chars        Method                System.Char get_Chars(Int32 get_Length       Method                System.Int32 get_Length() GetEnumerator    Method                System.CharEnumerator GetEnu GetHashCode      Method                System.Int32 GetHashCode() GetType          Method                System.Type GetType() GetTypeCode      Method                System.TypeCode GetTypeCode( IndexOf          Method                System.Int32 IndexOf(Char va IndexOfAny       Method                System.Int32 IndexOfAny(Char Insert           Method                System.String Insert(Int32 s IsNormalized     Method                System.Boolean IsNormalized( LastIndexOf      Method                System.Int32 LastIndexOf(Cha LastIndexOfAny   Method                System.Int32 LastIndexOfAny( Normalize        Method                System.String Normalize(), S PadLeft          Method                System.String PadLeft(Int32 PadRight         Method                System.String PadRight(Int32 Remove           Method                System.String Remove(Int32 s Replace          Method                System.String Replace(Char o Split            Method                System.String[] Split(Params StartsWith       Method                System.Boolean StartsWith(St Substring        Method                System.String Substring(Int3 ToCharArray      Method                System.Char[] ToCharArray(), ToLower          Method                System.String ToLower(), Sys ToLowerInvariant Method                System.String ToLowerInvaria ToString         Method                System.String ToString(), Sy ToUpper          Method                System.String ToUpper(), Sys ToUpperInvariant Method                System.String ToUpperInvaria Trim             Method                System.String Trim(Params Ch TrimEnd          Method                System.String TrimEnd(Params TrimStart        Method                System.String TrimStart(Para Chars            ParameterizedProperty System.Char Chars(Int32 inde Length           Property              System.Int32 Length {get;} 

This output is truncated a bit to fit in this book. However, you can see it includes every method and property of the String, and correctly identifies "Hello, World" as a "System.String" type, which is the unique type name that describes what we informally call a String object. You can pipe nearly anything to Get-Member to learn more about that particular object and its capabilities.

Variable Types

The fact that PowerShell is built on and around .NET gives PowerShell tremendous power, which isn't always obvious. For example, in Chapter 1 we explained that any PowerShell variable can contain any type of data. This occurs because all types of data-strings, integers, dates, etc-are .NET classes that inherit from the base class named Object. A PowerShell variable can contain anything that inherits from Object. However, as in the previous example with a string, PowerShell can certainly tell the difference between different classes that inherit from Object.

You can force PowerShell to treat objects as a more specific type. For example, take a look at this sequence:

 PS C:\> $one = 5 PS C:\> $two = "5" PS C:\> $one + $two 10 PS C:\> $one = 5 PS C:\> $two = "5" PS C:\> $one + $two 10 PS C:\> $two + $one 55 

In this example we gave PowerShell two variables: one contained the number five, and the other contained the string character "5." Even though this might look the same to you, it's a big difference to a computer! However, we didn't specify what type of data they were, so PowerShell assumed they were both of the generic Object type. PowerShell also decided it would figure out something more specific when the variables are actually used.

When we added $one and $two, or 5 + "5," PowerShell said, "Aha, this is addition: The first character is definitely not a string because it wasn't in double quotes. The second character one was in double quotes but well, if I take the quotes away it looks like a number, so I'll add them." This is why we correctly got ten as the result.

However, when we added $two and $one-reversing the order- PowerShell had a different decision to make. This time PowerShell said, "I see addition, but this first operand is clearly a string. The second one is a generic Object. So let's treat it like a string too and concatenate the two." This is how we got the string "55," which is the first five tacked onto the second five.

But what about:

 PS C:\> [int]$two + $one 10 

Same order as the example that got "55," but in this type we specifically told PowerShell that the generic object in $two was an Int, or integer, which is a type PowerShell knows about. So this time PowerShell used the same logic as in the first example. When it added the two, it came up with "10."

You can force PowerShell to treat anything as a specific type. For example:

 PS C:\> $int = [int]"5" PS C:\> $int | get-member    TypeName: System.Int32 Name        MemberType Definition ----        ---------- ---------- CompareTo   Method     System.Int32 CompareTo(Int32 value), System.Int Equals      Method     System.Boolean Equals(Object obj), System.Boole GetHashCode Method     System.Int32 GetHashCode() GetType     Method     System.Type GetType() GetTypeCode Method     System.TypeCode GetTypeCode() ToString    Method     System.String ToString(), System.String ToStrin 

Here, the value "5" would normally be either a String object or, at best, a generic Object. But by specifying the type [int], we forced PowerShell to try and convert "5" into an integer before storing it in the variable $int. The conversion was successful, which you can see when we piped $int to Get-Member revealing the object's type: System.Int32.

Note that once you apply a specific type to a variable, it stays that way until you specifically change it. For example:

 [int]$int = 1 

This creates a variable named $int as an integer, and assigns it the value 1. The $int variable will be treated as an integer from now on, even if you don't include the type:

 $int = 2 

It is still using $int as an integer because it was already cast into a specific type. Once set up to be an integer, you can't put other types of data into it. Here's an example of an error that occurred when we tried to put a string into a variable that was already specifically cast as an integer:

 PS C:\> [int]$int = 1 PS C:\> $int = 2 PS C:\> $int = "hello" Cannot convert value "hello" to type "System.Int32". Error: "Input string was not in a correct format." At line:1 char:5 + $int <<<< = "hello" PS C:\> 

However, you can recast a variable by reassigning a new, specific type:

 [string]$int = "Hello" 

That works just fine, and $int will now be treated as a string by PowerShell.

PowerShell isn't a miracle worker: For example, if you try to force it to convert something that doesn't make sense, it will complain:

 PS C:\> $int = [int]"Hello" Cannot convert "Hello" to "System.Int32". Error: "Input string was not in a correct format." At line:1 char:13 + $int = [int]" <<<< Hello" 

This occurred because "Hello" can't sensibly be made into a number.

This one's even more fun because it illustrates some of the advanced data types:

 PS C:\> $xml = [xml]"<users><user name='joe' /></users>" PS C:\> $xml.users.user name ---- joe 

In this example we created a string, but told PowerShell it was of the type XML, which is another data type that PowerShell knows. XML data works sort of like an object: We defined a parent object named Users and a child object named User. The child object had an attribute called Name, with a value of Joe. So when we asked PowerShell to display $xml.users.user, it displays all the attributes for that user. We can prove that PowerShell treated $xml as XML data by using Get-Member:

 PS C:\> $xml | get-member    TypeName: System.Xml.XmlDocument Name                        MemberType            Definition ----                        ----------            ---------- ToString                    CodeMethod            static System.Stri add_NodeChanged             Method                System.Void add_No add_NodeChanging            Method                System.Void add_No add_NodeInserted            Method                System.Void add_No add_NodeInserting           Method                System.Void add_No add_NodeRemoved             Method                System.Void add_No add_NodeRemoving            Method                System.Void add_No AppendChild                 Method                System.Xml.XmlNode Clone                       Method                System.Xml.XmlNode CloneNode                   Method                System.Xml.XmlNode CreateAttribute             Method                System.Xml.XmlAttr CreateCDataSection          Method                System.Xml.XmlCDat CreateComment               Method                System.Xml.XmlComm CreateDocumentFragment      Method                System.Xml.XmlDocu CreateDocumentType          Method                System.Xml.XmlDocu CreateElement               Method                System.Xml.XmlElem CreateEntityReference       Method                System.Xml.XmlEnti CreateNavigator             Method                System.Xml.XPath.X CreateNode                  Method                System.Xml.XmlNode CreateProcessingInstruction Method                System.Xml.XmlProc ... 

This demonstrates not only that variables are objects, but also that PowerShell understands different types of data, and provides different capabilities for the various types of data.

Curious about what object types are available? Here's a quick list of more common types (although there are more than this):

  • Array

  • Bool (Boolean)

  • Byte

  • Char (a single character)

  • Char[] (Character array)

  • Decimal

  • Double

  • Float

  • Int (Integer)

  • Int[] (Integer array)

  • Long (Long integer)

  • Long[] (Long integer array)

  • Regex (Regular expression)

  • Single

  • Scriptblock

  • String

  • XML

You will learn more about variables in Chapter 5. We'll also be popping in with details on these other types as appropriate throughout this book. Some of the types aren't frequently used in administrative scripting, so we will not arbitrarily hit you with all of them at once. Instead, we'll cover them in a context where they're used for something useful.

Variable Precautions

One thing to be careful of is PowerShell's ability to change the type of a variable if you haven't explicitly selected a type. For example:

 Write-host $a.ToUpper() 

This works fine if $a contains a string, as shown here:

 PS C:\> $a = "Hello" PS C:\> write-host $a.ToUpper() HELLO PS C:\> 

However, if $a was already set to an integer value you'll get an error:

 PS C:\> $a = 1 PS C:\> write-host $a.ToUpper() 

This occurs because, as an integer, $a doesn't have a ToUpper() method. You need to watch out for this when you're writing scripts that take input from other sources. For example, this might occur with a user or a file since this type of error can be tricky to troubleshoot. One way around it is to force PowerShell to treat the variable as the string you're expecting it to be:

 PS C:\> $a = 1 PS C:\> $a = [string]$a PS C:\> write-host $a.ToUpper() 1 PS C:\> 

You don't necessarily need to select a type up-front for every variable you use. However, you should be aware of situations that can make a variable contain a type of data other than what you originally expected.

.NET Conclusion

PowerShell is built on and around the .NET Framework, which means everything in PowerShell has a distinctly .NET flavor to it. On one level, you can ignore this and use PowerShell at a more simple level. For example, you can let it treat everything as a generic Object. However, as you grow with PowerShell, and want to leverage more powerful features, you'll find yourself gradually learning more about .NET.

This chapter wasn't meant to be a comprehensive look at .NET-that's another book entirely! Instead, the purpose of this chapter is to provide a rather a quick look at how .NET impacts the way PowerShell is built and the way PowerShell works. You'll see a lot more details about these topics-especially variables and their capabilities-throughout the remaining chapters.



Windows PowerShell. TFM
Internet Forensics
ISBN: 982131445
EAN: 2147483647
Year: 2004
Pages: 289

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net