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<T>. 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.
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:
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:
- If you’re executing a cmdlet, then the Parameters collection can be used to provide input arguments to the cmdlet call. For example, if
“Get-Process”, then you can add a
Nameparameter to the
Parameterscollection with the value set to an expression returning a string, and it will be the same as if you had invoked
“Get-Process -Name <value>”. I’m not 100% sure yet, but it would seem like this would only really apply if
IsScriptis unchecked (otherwise, it’s not very clear what you’re passing the parameters to).
- You can have WF push variables into the PowerShell runspace before the invocation. This is what the
PowerShellVariablesproperty is for. If you add a variable there call
Error, then the PowerShell expression in
CommandTextcan reference the value by using
$Error. Again, this would appear to be mostly useful when
Based on this, one might suspect that the
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.
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.
Handling pipeline output is only done in the
InvokePowerShell<T> 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.
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
Errorsproperty of the
InvokePowerShellactivity. To handle those, you’ll want to create a new variable in your workflow (of type
IEnumerable), and then bind it to the
Errorsproperty. Now you should be able to simply iterate over your variable right after
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.