Understanding output in PowerShell

Lately I have been programing quite a lot of PowerShell. The release of PowerShell 1.0 in 2006 and more recently version 2.0, is probably one of the best things that has happened to development on the Windows/.NET platform for a long time (even though it takes some time to get used to the “wackiness” of PowerShell ).

What is really interesting with Powershell is that is is fully integrated with .NET, everything is PowerShell is .NET objects, which makes it very easy to use existing .NET DLLs from PowerShell. In comparison to most other scripting languages I have used, instead of just being able to pass text between different scripts, PowerShell takes a more powerful approach and allows for passing .NET objects between the scripts.


To start with, take a look at the following example:

PS C:\dev> Get-Process Explorer

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    906      81    42620      59012   276     6,52    300 explorer


PS C:\dev> (Get-Process Explorer).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    Process                                  System.ComponentModel.Component

As we can see Get-Process is not just returning a string containing the description of the explorer process, it returns a System.ComponentModel.Component object. Be sure not to confuse what you see on the screen with what is actually returned by the CmdLet, Powershell uses output formaters to create a textual representation of objects. If we really want to capture the text output we could pipe our result into the Out-String CmdLet, like this:

PS C:\dev> (Get-Process Explorer | Out-String).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Output from functions
Now to one of the tricker concepts of Powershell if you are used to C# or a scripting language sush as Python. In PowerShell output from a function consists of everything that has not been captured in the function. For example, let us define this function:

function foo { "Hello"; return "world" }

The first time I saw Powershell my guess would have been that this function prints “Hello” to the screen and then returns “world”. However this is not the case, lets execute the function:

PS C:\dev> $result = foo
PS C:\dev> $result.Count
2
PS C:\dev> $result
Hello
world

As we can see, calling foo did not print “Hello” to the screen, and it did not just return “World”. It returned a list containing “Hello” and “world”. This is because of that everything in a function that is not captured gets returned from the function. Lets rewrite the function as we intended. Write-Host is a CmdLet to print to the console.

PS C:\dev> function foo { Write-Host "Hello"; return "world" }
PS C:\dev> $result = foo
Hello
PS C:\dev> $result.Count #returns nothing since it is not a list this time
PS C:\dev> $result
world

As we can see “Hello” gets printed to the screen when calling foo and “world” gets returned. So why do we need the return statement? The truth is that we don’t really. The reasons to use it would be to exit a function prematurely, and to make your code more readable.

A common source to many bugs when writing PowerShell scripts is not capturing output correctly, resulting that your function is returning more values than you expected it to do. So remember to take care of your output!

Peter

Leave a Reply

Your email address will not be published. Required fields are marked *