WF are not only for business (part 2): Marrying PowerShell into Workflows (Part 1 of 4)
Posted by Igor Moochnick on 02/13/2008
See other posts in the series “Workflows are not only for business”:
Part 1: “Workflows are not only for business logic, or how to define an SMTP protocol state machine in a Workflow.”
Nowadays the complexity of the management systems and management-related processes reaches the new heights. This is a theme for a separate discussion and not the scope of this post, but, as I like to say, it can be attributed to a simple fact: “because we can do so!” 🙂 Actually what I mean here is the processing power of the current systems and the flexibility of the tools allow us this.
All this means that there is never-ending race for creating better and simpler tools for the administrators and for the system analysts to define and seamlessly implement complex processes, such as:
To make my point lets discuss a “down to earth” example. Let’s say we have a server farm that stores and manages customers media content – something like YouTube. Imagine how many tasks are involved to make such system tick, like: content conversion, distribution, expiration, etc… Note that I haven’t even mentioned the usual suspects like: backups, account management, etc… These tasks are constantly changing and evolving with the system. This means they should be adjusted accordingly in timely manner. As you you know it’s pretty mundane to write and update the code as well as the shell scripts. As I see it, the workflows are the perfect candidate to take off (or, at least, relax) the management overhead.
Hmm… Let’s see what do we have laying around that can help us in this quest. We have an amazing tool for the analysts to define the processes – the Workflows, and another, not less amazing and extremely flexible, tool, fine tuned for solving most of the IT-related issues – the PowerShell. A match made in haven 😉
Thinking how many different scenarios can benefit from the PowerShell flexibility, makes me ask a question: “Why not to make the PowerShell a first-class citizen in the Workflows?”
[The picture on the right is a teaser and shows a possible (exaggerated) scenario. I’ve put the Xceed controls as a thank you to Xceed for thinking about the community and providing community version of their controls for public use]
Continue reading for more information about using and implementing the PowerShell activities …
“Simple” PowerShell invocation activity
Let’s start simple: PowerShell has a great pretty-well documented integration interface. Why don’t we try to create a simple custom activity that will host a PowerShell instance and will run a specified script.
On the right you can see (as an example) a simple Workflow that hosts a PowerShell activity that calls a WMI script to extract a free disk space for a drive C:. [And, Yes, I know it can be done in 100 different ways – it’s just an example of a custom activity]
This activity exposes a set of the following properties and events:
This activity initializes a PowerShell instance, fills-up the input script pipeline with the data, stored in (or bound by) the ScriptInput dependency property, calls the provided script and exposes the script’s output via the ScriptOutput property – as simple as that.
The code of the Execute method is as straightforward as it can be (try/catch is omitted for simplicity of the presentation):
Having ScriptInvoke in your toolbox allows you to define almost any management scenario, that you can think of, using the Workflow “language”. So there can be no more excuses that the workflows can’t be used for the systems management.
Taking it to the next level. Think “advanced scenarios”.
The described above simple activity is pretty powerful as it is, but it is not really flexible to fit into a complex workflows. Imagine a scenario where a decision. if a script should be executed or not, should be controlled by a set of rules. These rules are evaluated in the scope of the information generated by a previously executed script (or series of scripts or code). For example: [rule] if there is only 10% of the free disk space available [do script action] find all the large files on the disk and compress them.
In this case a policy activity and another script activity should be added to the Workflow. The, described in the previous chapter, simple implementation of the PowerShell Invoke Activity, when it’s called a second time, will create yet another instance of the PowerShell. This means, in the current implementation, the scripts can’t communicate via the stored variables, but only via files, Workflow properties/variables or other non-PowerShell-friendly means.
We need to take the PowerShell instance out of the script execution scope and manage it outside. You can get this behavior by using the PowerShell Scope Activity (see the external activity on the sample Workflow pictured on the right). This activity inherits its behavior from the Sequence Activity and is not different from it in any way, but from a single and important fact: it holds a reference to a PowerShell instance. All the activities, dropped on its design surface, have an access to this PowerShell instance (via the attached PowerShell dependency property) as well as any activity outside of the scope (just bind to the exposed PowerShell dependency property).
As an added bonus (note the grayed-out PowerShell property on the Properties Grid): all the PowerShell-related activities will auto-detect the parent Scope activity and will automatically reuse its PowerShell instance, reducing the configuration overhead during the design time.
To make life easier, I’ve taken the most common task performed in the PowerShell, like set and read variables, and extracted it into a separate stand-alone Variable Action activity. It’s a single activity that morphs itself depending on the action you’ve chosen. Note: the activity changes it’s presentation (icon and text) as well as controls what properties are shown on the Properties Grid.
As you can see, these new PowerShell activities are pretty user-friendly: script is shown on the design surface, the shape is realizable, etc… There are so many great little implementation details, I had to solve to get everything right, I just can’t cover them in a single post. So I wont go too deep into the details in this post (it’s getting pretty big) but I’ll try to cover most of them in the following series of posts.
Extending Workflow Authoring experience
Couple of words about the design experience. Workflow designer, hosted by the Visual Studio (we’ll talk in the following posts how you can re-host it in your application), follows the same paradigm as the rest of the well-known designers in VS environment, like form designers, Class Designers, etc… You can shape and form the way your activity is presented and controlled by the user. You can add properties, menus, dialog boxes, etc… – anything you can think of.
On the right you can see a small example of how you can extend the control of your activities:
Double-clicking the Script Activity shape brings a script editing dialog box (see it transparent on the top left)
Right-click Menu item is added (bottom center)
Grid action is added (bottom right)
At this moment the information on how to do this (and other designer extensions) is not readily available and very scarcely documented. Some areas are widely used, so you can find a lot of samples on the Internet, some of the areas are not – here the old try-and-error technique is your only option. Note: if something fails – you have almost to no explanation why. Be always ready to roll-back your code.
I’ve gathered an enormous amount (enough for a good size book) of information and samples while playing with the WF designers. I’m planning to publish it on some Wiki site as soon as I’ll find some reputable host (JostSot looks promising, but have to wait until the end of integration with Google).
Limitations (what you need to keep in mind)
Current implementation of the PowerShell Scope activity does not prevent you from putting Listen, Event-Driven, Delay or other idling activities. Nothing prevents the Workflow Runtime from offloading the Workflow and persisting it. But… There is no way to persist a PowerShell runtime state, so the workflow will loose all the accumulated data in its instance. The current implementation of the PowerShell Scope Activity will easily recover from the Persistency state and your Workflow will resume without any errors, but, as I said, the state of the PowerShell instance will be lost. In simple words: any changes in the PowerShell variable can’t be restored [nor any other initialized objects in the runspace].
There are a couple of ways you can solve this situation:
You can try to use the SetVariable or Script activities to reset your variables values
You can try to persist your variables manually
Or, in a more generic case, you can fall back into using the simple ScriptInvoke activities (described at the beginning of this post)
The current implementation is not nearly covering all the possibilities of the PowerShell integration into the Workflows, but, merely, a good starting point for engineers that see a need in adding more power to their Workflows. You’re welcome to use the provided code in any of your projects, but don’t forget to mention my name in the credits :-).
Let me know how are you using Workflows outside of their natural “habitat” and I’ll be happy to mention your project in my Workflows-related presentations.
Note: I’ve marked a lot of places with “IP:” comment – this is an interest point like you have in your travel destinations. I’ll do my best to cover all of them in my following up posts, so stay tuned.
WF are not only for business (part 3): Marrying Workflows into PowerShell (series)
Construction of the dynamic script pipes and data flows in Workflows
Controlling activity’s properties presentation in PropertyGrid
Creating custom properties’ editors
Controlling workflow’s serialization
Some people complained that they can’t find the source code, so take it [here].