Friday 29 March 2013

Hashtables in Powershell

Hashtables are good for creating dictionary-like data structures in Powershell, for look-ups and related functionality. The following powershell script code shows how to create a Hashtable in Powershell and to use and modify this datastructure:
$countries = @{            
    "Norway" = "Oslo";            
    "Denmark" = "Copenhagen";            
    "Sweden" = "Stockholm";            
    "Germany" = "Berlin";            
    "Italy" = "Rome";            
    "Burkina Faso" = "Ougadougou";            
};             
            
            
$countries.'Burkina Faso'            
$countries.ContainsKey('Norway')            
$countries.ContainsValue('Ougadougou')             
$countries.ContainsValue('London')            
$countries['Sweden']             
$countries.Add('France', 'Paris')             
$countries.France             
            
$countries.Remove('Burkina Faso')             
            
$countries.ContainsKey('Burkina Faso')
The code above creates a hashtable using the @{ and } literals, where each key and value is defined by key = value followed with a semicolon, note that this is optional and can be omitted. Hashtables are very user-friendly in Powershell. One can address a value in the hashtable by passing in the key in square brackets, like an index. It is also possible to perform manipulation of the hashtable, using Remove and Add. For the Add method, one supplies the key and value pair to add. For the Remove method, one supplies to the key to look for and then remove (this will of course also remove the value of the key-value pair).

It is also possible to query the hashtable using ContainsKey and ContainsValue methods, looking for keys or values. Note also that members of the hash table is available and shown in Intellisense using the Powershell ISE (Integrated Shell Environment). It is possible to say $countries.France, or $countries.'Burkina Faso'. The last hash table key address is encapsulated in quotes, since there is a space in the key. When calling GetType() on the hashtable instance $countries, the name Hashtable is shown.

To list up the keys and the values of a hashtable, use the Keys or Values member of the hashtable. Example:
$countries.Keys            
$countries.Values

Keyboard input in Powershell

Keyboard input in Powershell

Asking users for input in Powershell is very straight-forward. Use the Read-Host cmdlet in Powershell and add a string value to the -Prompt switch of the cmdlet to specify which text to display to the user. Assign the result from Read-Host to a Powershell variable, e.g. $myvariable. This variable can then be treated logically and control the further program execution and logical flow of the program.

The following code shows how this can be done:

            
function Ask-FavoriteColor ([int] $personsToAsk){            
<#
    .SYNOPSIS
    Ask about the favorite color
    .DESCRIPTION
    The favorite color was asked in the movie "Holy Grail"
    .PARAMETER personsToAsk
    The number of persons to ask
#>            
 foreach ($i in 1..$personsToAsk){            
            
  [string] $color = Read-Host -Prompt "What is your favorite color?"            
            
  if ($color.ToLower() -ne "blue"){            
     Write-Host "You didn't say blue!"             
  }            
  else {            
     Write-Host "Good choice!"             
  }            
 }            
            
}            
            
Ask-FavoriteColor 2


If you see the text at the top of the function, you will see how one can document the function using meta keywords such as .SYNOPSIS and .DESCRIPTION. When using the Powershell cmdlet Get-Help, e.g. Get-Help Ask-FavoriteColor -detailed, one will see the (detailed) documentation in the Powershell help page. This is rather equivalent to the obiqutous man command seen in Unix-based systems.

When creating Powershell functions, your functions should be documented using this technique. There are lots of other meta keywords that can be used. See this overview for meta keywords for documentation.

PS C:\Users\Tore Aurstad\Documents\Powershell Scripts\files> C:\Users\Tore Aurstad\Documents\Powershell Scripts\Input\KeyboardInput.ps1
What is your favorite color?: red
You didn't say blue!
What is your favorite color?: blue
Good choice!

'
PS C:\Users\Tore Aurstad\Documents\Powershell Scripts\files> Get-Help Ask-FavoriteColor -Detailed NAME Ask-FavoriteColor SYNOPSIS Ask about the favorite color SYNTAX Ask-FavoriteColor [[-personsToAsk] ] [] DESCRIPTION The favorite color was asked in the movie "Holy Grail" PARAMETERS -personsToAsk The number of persons to ask This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer and OutVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). REMARKS To see the examples, type: "get-help Ask-FavoriteColor -examples". For more information, type: "get-help Ask-FavoriteColor -detailed". For technical information, type: "get-help Ask-FavoriteColor -full".

Exception handling in Powershell scripts

Exception handling in Powershell

Powershell is capable of handling exceptions in your Powershell scripts. Instead of the familiar try-catch construct, you use the trap keyword. The trap keyword followed by a block clause for handling the exception can be anywhere inside a Powershell function, at the top, middle or bottom of the method. I would suggest keeping the trap keywords at the bottom for readability. After all, your function's code is what is most important and exception handling is secondary. Still, the scripts should contain good exception handling for expected errors. In addition, a universal exception handler can be achieved by trapping the [System.Exception] exception, i.e. any exception. It is though better to trap the expected exceptions and unexpected exceptions should be thrown. 
#clear screen first using Clear-Host             
Clear-Host             
            
function Divide([int]$a, [int]$b){            
            
 $answer = $a / $b;            
 Write-Host $answer             
            
 trap [System.DivideByZeroException] {            
    Write-Host Attempted to divide by zero!            
    continue            
 }            
 trap [System.Exception] {            
    Write-Host Unexpected Exception. Breaking out of function.            
    break            
 }            
            
}            
            
Divide 15 3            
Divide 75 15            
Divide 95 5            
Divide 111 0            
Divide 64 8            
Divide 4 2.3             
            



As seen in the Powerscript code above, the trap keyword is followed by the error handling code. Usually, doing a Write-Host or logging the error is what will be done here (Write-Host corresponds to Console.WriteLine) in .NET based programming languages.

It is possible to have multiple trap statements with individual Exception types. In this example, the [System.DivideByZeroException] is handled. The keyword continue basically means that execution is permitted to continue. In the other trap statement, the keyword break is used. This basically is the same as a throw statement in a corresponding try-catch clause, where program execution is halted in the function. Judge which exceptions should be allowed to continue, and which exceptions should be allowed to break.

This is just another example of how powerful Powerscript is when it comes to a shell script. Of course, shell scripting languages such as Perl sports most of the functionality. The ability of Powershell to make use of .NET (after all Powershell is built upon .NET), means many .NET developers will quickly find new uses of Powershell by making use of previous knowledge and experience in .NET.

To sum up, your Powershell scripts should have the necessary trap statements for error-handling. As a sidenote, I do not like the keyword trap, they should have called it catch or something more trustworthy ..