PowerShell Pipeline

Working with Object Types in PowerShell

Understanding what's going on in the background of your code will up your efficiency in PowerShell.

Whenever you use PowerShell, whether it is querying data or making a change to some configuration or existing object, you are working with different types of objects. You may not be aware of it because all of the work is happening behind the scenes in the script, but everything that you query or work with is an object such as a string or a larger object with multiple properties that may have other nested objects within it.

Let's look at the simplest of the object types, the string. Something simple such as "Hello World", when sent to Get-Member, shows up as a System.String.

"Hello world" | Get-Member

Figure 1.

I'm not too interested today in looking at all of the methods and properties of the object itself, just the object type. If I do the same thing with a number such as 9, then we would see the object type come back as a System.Int32.

What if we had used "9" instead and sent it to Get-Member? Would it be an Int32 or would it become a string instead? Let's take a quick look and see what happens.

PS C:\> "9" | Get-Member TypeName: System.String

We end up seeing our "9" as a string because of the quotes that we used around it. When you import data from a file such as a CSV or a TXT document, there will be numbers that perhaps you would like to sort on, but because they are a string, it becomes pretty inaccurate. The same goes if you are trying to add string values of the numbers as shown below.

PS C:\> "9" + "9"

99

Last time I checked 9+9 is 18, not 99. Because they are strings, PowerShell will instead append the string data instead of actually adding the values together like we would have expected. Instead we would need to use a technique called "casting" to convert the string values into actual integers. We have a couple of approaches to make this work.

The first technique is to use the type operator to cast each of the strings to an integer.

PS C:\> [int]"9" + [int]"9"

18

This approach may seem familiar and if it does, it is because this is commonly used when working with parameters in functions and scripts.

Param (

[string]$Name,

[int]$Age,

[datetime]$Birthdate

)

By explicitly assigning a variable as a specific type, you can prevent improper data being assigned to the parameter. This same approach can be applied to your day to day variables to provide the same type of data protection.

[int]$Item = $Null

$Item = 'test'

[Click on image for larger view.] Figure 2.



$Item = 8

$Item

Figure 3.

The other technique is to make use of the –as operator to convert an object from one type to another.

PS C:\> "9" -as [int] | Get-Member TypeName: System.Int32

If you have ever worked with Read-Host, you may have found that the data being returned is always a string regardless of what was typed at the prompt, such as a date or number. The trick to enforcing the data is to use a type operator to enforce the expected type.

[datetime]$Date = Read-Host 'Enter a date (dd/mm/yyyy)'

$Date.GetType().Fullname

Figure 4.

Trying to force a value which is not of the datetime type will throw an error.

[Click on image for larger view.] Figure 5.

Types are not just for enforcing a particular kind of object in your scripts or making adjustments to allow data to play nice together. It can also be used for validation of data as well such as the case when working with IP addresses. Regular expressions are a great way to provide validation of an IP addresses but can become very complex depending on the level of validation. A simple RegEx might just test for the 4 octets but doesn't take into consideration invalid IPs like 330.123.45.222. Using a type operator of [ipaddress] helps to mitigate this issue by ensuring that the data presented is always a valid IP, otherwise an error will be thrown.

PS C:\> [ipaddress]'192.168.1.1' Address : 16885952

AddressFamily : InterNetwork

ScopeId :

IsIPv6Multicast : False

IsIPv6LinkLocal : False

IsIPv6SiteLocal : False

IsIPv6Teredo : False

IsIPv4MappedToIPv6 : False

IPAddressToString : 192.168.1.1 PS C:\> [ipaddress]'345.192.56.78'

Cannot convert value "345.192.56.78" to type "System.Net.IPAddress". Error: "An invalid IP address was

specified."

At line:1 char:1

+ [ipaddress]'345.192.56.78'

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidArgument: (:) [], RuntimeException

+ FullyQualifiedErrorId : InvalidCastParseTargetInvocation PS C:\> [ipaddress]'2001:db8:a0b:12f0::1' Address :

AddressFamily : InterNetworkV6

ScopeId : 0

IsIPv6Multicast : False

IsIPv6LinkLocal : False

IsIPv6SiteLocal : False

IsIPv6Teredo : False

IsIPv4MappedToIPv6 : False

IPAddressToString : 2001:db8:a0b:12f0::1

That is all today about working with object types in PowerShell. You can now take this knowledge and hopefully use it in your scripts to provide enforcement of variables and cast objects to their new types.