vs10_wf_ps I’ve been fooling a bit with the new Windows PowerShell-related activities included in Windows Workflow Foundation 4.0 alongside the Visual Studio 2010 Beta 1 release. It’s pretty cool seeing PowerShell being directly supported right out of the box!

There are two different activities: InvokePowerShell and InvokePowerShell. The difference (as far as I can see) is that the latter allows you to capture the output of the PowerShell command being executed (that is, the results from the pipeline). I can understand why both variants might be needed, but not thrilled about the naming. At the least, it’s not immediately obvious what the difference between the two is, so it’s going to be confusing.


Using InvokePowerShell

I struggled a bit understanding how the InvokePowerShell activity was meant to be used. In particular, I didn’t grasp immediately the significance of the IsScript property of the activity:

vs10_wf_ps_params

If I understand it correctly, here’s the key difference: If IsScript is not checked (the default), then CommandText cannot be an arbitrary PowerShell expression. Instead it must be the name of the PowerShell cmdlet to invoke, but you cannot add any extra information there (such as the value of a parameter). By contrast, if IsScript is checked, then CommandText can be a list of (more or less) arbitrary PowerShell expressions, including variable declarations and all.

I believe that for a lot of people, enabling IsScript will make the activity behave in a more natural way.

There are a few more interesting details about the PowerShell activities:


Passing Data into PowerShell

There are two ways to pass data into the PowerShell script to execute:

  1. If you’re executing a cmdlet, then the Parameters collection can be used to provide input arguments to the cmdlet call. For example, if CommandText is “Get-Process”, then you can add a Name parameter to the Parameters collection with the value set to an expression returning a string, and it will be the same as if you had invoked “Get-Process -Name . I’m not 100% sure yet, but it would seem like this would only really apply if IsScript is unchecked (otherwise, it’s not very clear what you’re passing the parameters to).
  2. You can have WF push variables into the PowerShell runspace before the invocation. This is what the PowerShellVariables property is for. If you add a variable there call Error, then the PowerShell expression in CommandText can reference the value by using $Error. Again, this would appear to be mostly useful when IsScript is checked.

Based on this, one might suspect that the Parameters and PowerShellVariables properties are basically there to support both modes of operation of the activity: One when invoking a cmdlet directly and one when executing a more free-form script. Is this good? I’m not sure yet. I can see a sort of logic to both ways of using the InvokePowerShell activity, but it seems a bit complex and potentially confusing. I sure know I was confused the first time I tried to use it.


Pipeline Input

It should be obvious by now that I wasn’t exactly right when I said there were two ways to pass data into the PowerShell script. There’s a third (main?) one: Provide an object (or collection of objects) as the pipeline input, which is what the Input property of the activity is for.

It should be fairly obvious how to use it: If the command is a cmdlet, then the input will be feed just like if you had piped something to it in PowerShell. You might expect that if the command is a free-form script, then you’d be able to access it the inputs $_; however, I haven’t been successful in that so not sure if it’s supported.


Pipeline Output

Handling pipeline output is only done in the InvokePowerShell activity, and it’s basically very simple: When adding the activity to your workflow, the designer will ask you to bind T to a type, and that’s what you expect your PowerShell command to return. I can imagine that in most cases, this should be some sort of collection (like IEnumerable) since most PowerShell commands will return multiple objects.

Then, just bind the Output property of the activity to a variable in your workflow that will receive the pipeline output after the activity executes.


Pipeline Errors

Errors resulting from executing the InvokePowerShell activity can surface in one of two ways:

  • Certain errors, such as trying to invoke a malformed expression or a non-existent cmdlet will result in an exception being thrown and the Workflow faulting, unless you have the activity inside try/catch blocks.
  • Anything that gets written by the command to the error stream (through the Write-Error cmdlet) will get exposed through the Errors property of the InvokePowerShell activity. To handle those, you’ll want to create a new variable in your workflow (of type Collection or just IEnumerable), and then bind it to the Errors property.  Now you should be able to simply iterate over your variable right after InvokePowerShell finishes executing.

Designer Support

I’m not totally happy with the designer support for the PowerShell activities. Besides my general complaints about the Workflow Designer (a subject for another blog post), there’s something that really bugs me: There’s no proper editor support for entering the CommandText in the activity.

Sure, you can attempt to write your script directly into the text editor in the activity designer, but that’s way too small for anything more complex than, say, calling Get-Process. You could also attempt to use the property window, but that’s even worse because all it has is a single-line text box. At the very least, it needs to popup into a multi-line text editor window.


Tomas Restrepo

Software developer located in Colombia.