PowerShell Basics: Primitive data types

One of the best things about PowerShell is how easy it is to use. It is a good idea to know a little bit about whats going on under the hood though. Although you can manage fine doing most things in PowerShell without thinking about data types, knowing about them will really help you understand what is going on and hopefully help you spend less time debugging your scripts.

 

What is a datatype?

Straight off Wikipedia: data type is a classification identifying one of various types of data.
Now that’s not really very helpful, is it?

Think of it like this:

If you have a number, lets say 2 – PowerShell would by default store that as a 32-bit integer – which is basically a fancy word for a number without decimals. Integer values cannot have decimals.

Lets try a different number, 2,4 – PowerShell would by default store that as a 64-bit value with a data type called a “Double”. Double values are for numbers with decimals, also known as precision numbers.

One of the most used data types and most significant is the “String”. A String is a collection of characters. When defining a string value, we always enclose the value in double quotes. like this:

 $String = "Hello" 

Open your shell and try the command without double quotes. Spoiler: You’ll get a big red error message.

A detailed list of data types for .NET can be found here: http://msdn.microsoft.com/en-us/library/47zceaw7(v=vs.71).aspx

Short demonstration if you haven’t already done so yourself:

Note the method gettype(). You can use that on any object to figure out the data type, it is very useful during debugging.

 

Usage in PowerShell

As we have already seen, PowerShell chooses the appropriate data type for us, allowing us to think about other things. But if we really want to have full control we can specify it ourselves like this:

[Int32]$number = 2
[Double]$number2 = 2.4
[String]$string = "hello"

Remember how Integers cannot have decimals? Try this and see what you get:

[Int32]$number = 2.4
Write-Host $number

Because Integers cannot have decimals, it rounds the number to the nearest non-decimal number.

Again I would like to stress the usefulness of the method gettype(). Get into the habit of using it and you won’t be wondering what data type your script is returning.

 

Enough boring theory! Why is this useful?

Consider the following code:

$number1 = "2"
$number2 = "2"
$number1 + $number2

Without knowledge of data types you might think the result would be 4.
However, because we enclosed the values in double quotes, the variables have become Strings instead of Integers. Add the two Strings and you get “22”.

Now consider this code:

[Int32]$number1 = "2"
[Int32]$number2 = "2"
$number1 + $number2

This time we have told Powershell to use Integers as our data types and get the expected result 4.
Note that what we are doing here is actually defining $number1 and $number2 as Strings and then converting them to Integers. This is a technique known as ” typecasting”.
If we wanted Integers we should not have used double quotes in the first place.

As we can see in the above examples, getting the type wrong can result in unexpected results.

Perhaps the most useful place to specify data type, is when defining parameters for a function. Validating input is very important and defining which data type you use will be very useful in the validation process. Think about it – When you ask for a user to enter his or her age, you expect something like 25 or 40. You don’t want your script to continue if the user types “Banana” or 42,6.

PowerShell basics: Variables

Many Windows Administrators use PowerShell for its shell purposes but anyone with a scripting or programming background will want to use it for its scripting capabilities. In this post I’ll cover the basic usage of variables in PowerShell.

 

What are Variables?

Variables are nothing more than placeholders for information or for a value. Each variable is defined with a name and the name is used as a reference to whatever is stored in the variable. Variables are useful to store information you want to use later, or to cache the information so you don’t have to keep querying the same information over and over again. Any type of data may be stored in a variable.

 

Usage in PowerShell

PowerShell variables always start with a dollar sign ($) and are followed by the variable name like this: $variable. Values are assigned using the equals operator (=). Note that variable names in PowerShell are not case-sensitive. $hello and $Hello are the same thing. People with experience from strongly typed languages may notice there is no need to explicitly define the datatype. although you could type [int]$number = 1, there is no need as PowerShell will figure it out. It is useful in certain circumstances though.
Let’s try it:

In the example above, we created a variable called $hello and assigned the value “Testing variables!”. We then created another variable called $number and assigned the value 123. Notice the arithmetic operation at the end where we used our variable $number and added 1.

Using WMI with PowerShell

If you aren’t already using WMI to retrieve information from computers in your domain, it’s time to get started. WMI is a goldmine of information and it’s never been easier to access.

I’ll be covering WMI in more detail later as there is so much to go through. For now I’ll demonstrate a short script that can reveal how easy it is to generate useful reports when accessing WMI through PowerShell.

This function will take an array of computer names, attempt to query each of their WMI databases, retrieve the free space available and also calculate the free space percentage. The function accepts pipelining. I have not added any error handling which means if a machine is not configured to let you query its WMI database, you will get a big red error telling you so. Don’t worry though, you can do no damage with the function as it does not set any values. Here is an example of usage and output:

And here is the source

Function Get-FreeSpace {
param(
[Parameter(ValueFromPipeline=$true)]
[String[]]$Computers
 )

 Begin {
 $Result = @()

 }

 Process {
 $Drives = Get-WmiObject 'Win32_LogicalDisk' -ComputerName $Computers | where { $_.DriveType -eq 3 }

 $Drives | % {
 $newobj = New-Object System.Object
 $newobj | Add-Member -Name Server -MemberType NoteProperty -Value $_.__Server
 $newobj | Add-Member -Name DriveName -MemberType NoteProperty -Value $_.Name
 $newobj | Add-Member -Name FreeSpace -MemberType NoteProperty -Value ("{0:0.00}GB" -f ($_.FreeSpace / 1GB))
 $newobj | Add-Member -Name Size -MemberType NoteProperty -Value ("{0:0.00}GB" -f ($_.Size / 1GB))
 $newobj | Add-Member -Name PercentFree -MemberType NoteProperty -Value ("{0:0.00}%" -f ($_.FreeSpace * 100 / $_.Size))
 $Result += $newobj
 }
 }

 End {
 return $Result
 }

}

Allow Dial-in and assign static IP Addresses in Active Directory with PowerShell

So it turns out setting IP addresses in Active Directory with PowerShell is not quite as straight forward as you might expect. It is perfectly possible though, lets have a look at how it works.

Just so we are on the same page, this is what we are looking at – our Dial-in tab in AD:

By default, Network Access Permission is set to “Control access through NPS Network Policy” and there is no assigned IP address.

First let’s take a look at which attributes are affected:


These attributes are set when we set the Dial-in tab as shown in the caption above.

The first thing you might be wondering is what on earth 169090600 is. It is in fact our IP address 10.20.30.40 as an Integer representation of the 32bit binary that is the IP address.
That is 10.20.30.40 = 00001010.00010100.00011110.00101000.
Remove the dots and you get 00001010000101000001111000101000 = 169090600.

Now that we know what we are dealing with, let’s get to the PowerShell part of it.
The first thing we have to do is convert our IP from 10.20.30.40 to 169090600. I wrote a quick function to do just that.


function Convert-IP {
 param(
 [Parameter(ValueFromPipeline=$true)]
 [String]$IPAddress = "127.0.0.1"
 )

 $octetsDecimal = $IPAddress -split "\."
 $octetsBinary = $octetsDecimal | % { [convert]::ToString($_, 2) }

$octetsBinary = $octetsBinary | % { ("0" * (8 - $_.length)) + $_ }

$octetsBinary | % { $binaryIP += $_ }
 $integerIP = [convert]::ToInt32($binaryIP, 2)

 return $integerIP
}

Setting the attributes in AD is simple

Set-QADUser -Identity "Testuser" -IncludedProperties @("msNPAllowDialin", "msRADIUSFramedIPAddress", "msRASSavedFramedIPAddress") -ObjectAttributes
@{msNPAllowDialin=$true;msRADIUSFramedIPAddress=169090600;msRASSavedFramedIPAddress=169090600}

Combine the two and you can make this task painless

$IP = Convert-IP "10.20.30.40"
Set-QADUser -Identity "Testuser" -IncludedProperties @("msNPAllowDialin", "msRADIUSFramedIPAddress", "msRASSavedFramedIPAddress") -ObjectAttributes @{msNPAllowDialin=$true;msRADIUSFramedIPAddress=$IP;msRASSavedFramedIPAddress=$IP}