Saturday, September 04, 2010

Calling Functions in PowerShell

I spent quite a bit of time earlier this week with a problem in calling worker functions. In a PowerShell script, or a PowerShell session, if there are a set of commands you run more than once or twice, one thing you can do is to put them into function then just call the function rather than typing out all the individual commands. Worker functions can make scripts a lot shorter. You can see an example of a worker function over here: In that example, you can see a worker function, DisplayValues (begins at line 45), which I then call several times in the script.

The problem I had this week was that for some reason, the worker function was spewing out nothing like what I was expecting. I started at the code for some time before spotting the problem – I’d not use the right calling process to invoke the function. A typical newbie mistake.

In .Net method calls, you state the name of the object, a “.” followed by the method name, and a parameter list enclosed in parentheses:  $object.method($a, $b, $c).  But a function is called without the parentheses, and the  parameters are space, not comma delimited, or function $a $b $c.

To illustrate this problem, I’ve written a little script that defines a worker function then calls it several ways:

function wf1 {
param (    $a, $b, $c)
"`$a:" ; $a; ""
"`$b:" ; $b; ""
"`$c:" ; $c; ""

wf1  "Foo",'Bar',"foobar"
wf1  "Foo" 'Bar' "foobar"
wf1 –c “foobar” –a “Foo” –b “Bar:

The output from this is left as an exercise for the reader!

Now the first two times the script calls the worker function, PowerShell assigns the array (i.e the stuff delimited by commas) to the first parameter, leaving the second two parameters empty. Not what you want. The second two examples call the worker function correctly. Arguably the last of the calling sequence is better from a production orientated point of view.

On interesting thing – all four of those calling sequences ‘works’ and by default presents no apparent errors. However, if you set strict mode (Set-Strictmode) and setting version to 2 would warn that the first call was in error like this:

PSH [C:\foo]: . 'C:\Users\tfl\AppData\Local\Temp\Untitled5.ps1'
The function or command was called as if it were a method. Parameters should be separated by spaces. For information about parameters, see the about_Parameters Help topic.
At C:\Users\tfl\AppData\Local\Temp\Untitled5.ps1:8 char:4
+ wf1 <<<< ("Foo",'Bar',"foobar")
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : StrictModeFunctionCallWithParens

Now had I had the relevant line set in my profile, I’d not have wasted an hour wondering why things were not working.


jv said...

Ha! Got you too.

The owners created this as a test to see who was listening I am sure.

Using the 'strict' option is an excellent idea. Thanks.

Unknown said...

Nice thanks.