Windows PowerShell: Looks a lot like a workflow

Each month this year, Don Jones will present an installment in a 12-part tutorial on Windows PowerShell Workflow. We encourage you to read through the series in order, beginning with the January 2013 column.

Don Jones

Workflows look and feel a lot like Windows PowerShell functions or scripts—but they’re not. That similarity is only skin-deep, and perhaps it doesn’t even extend all the way through the skin.

You have to always remember that Windows PowerShell must translate workflows into a totally separate technology—Windows Workflow Foundation (WF). That means you can only do things that can be duplicated in WF. Your code will then run in an entirely different kind of environment that has its own rules and restrictions.

Run any script as a workflow

The easiest way to run a workflow is to simply run any standard Windows PowerShell script as a workflow. You can do this with the Invoke-AsWorkflow command. This command lives in the PSWorkflow module, although Windows PowerShell version 3 should be able to discover and run the command without you needing to explicitly load the module first. This command essentially wraps your entire script in an InlineScript block, meaning it runs within WF as a single step.

That means you don’t have to worry much about Windows PowerShell Workflow restrictions. However, you also don’t get to take advantage of certain Windows PowerShell Workflow features, like the ability to resume an interrupted process. Your “process,” in this case, will consist of the entire script running in a single step. There’s no way for that to resume midway through if you have to pause or interrupt. Here’s an example, in which I’ve created a script block with a few commands and then run them as a workflow:

$script = { $name = Get-Content Env:\COMPUTERNAME $name | Out-File c:\MyName.txt Get-Service } Invoke-AsWorkflow -Expression $script -PSComputerName DC,CLIENT

One reason I used a variable here was to demonstrate that WF runs all of this as a single InlineScript. Keep in mind that every command WF runs gets its own, fresh environment. There’s no built-in way to persist data between commands. That means variables are natively pretty useless. However, because this whole thing is implicitly wrapped as a single-step InlineScript, the variable I created will persist throughout.

So why would you bother? Windows PowerShell Workflow still gives you a few additional advantages. There are a certain number of parameters shared by all workflows. These let you specify things such as target computer names and so on. Your script will inherit a basic infrastructure for multi-computer work. For long-running scripts, you can kick off a workflow, then disconnect from the remote computer while the workflow continues running, which is nice.

Formal workflow syntax

Here’s a very simple workflow:

Workflow New-Server { Get-Content -Path Env:\COMPUTERNAME | Out-File -FilePath C:\MyName.txt Get-NetAdapter -Physical } New-Server -PSComputerName CLIENT,DC

Workflows are a kind of Windows PowerShell command, like a cmdlet, script or function. That being the case, you can run them simply by calling their name, as I’ve done on the last line of this example. Remember, workflows all inherit a certain number of built-in parameters, like –PSComputerName. Workflows also rely on the Windows PowerShell Remoting feature, which is enabled on both computers in this example.

The practical upshot is that both commands in the workflow are being run right on the remote computers, with the results coming back to my computer. I didn’t have to code any of that or even create a computer name parameter. I didn’t have to enumerate the computer names, create connections or anything else. Windows PowerShell Workflow does it all for me. There’s absolutely nothing in this script I couldn’t have achieved without Windows PowerShell Workflow—it would just require a bit more work on my part.

You’ll notice I’ve spelled out the command names in my workflow. I’ve also used named parameters in every instance. That’s always a best practice in any Windows PowerShell script, but it’s mandatory in a workflow. You can’t use positional parameters. You have to spell everything out or you’ll get an error.

Now check out this workflow (not that you’ll need to import the PSWorkflow session into your shell instance in order for the “Workflow” keyword to be legal):

Workflow New-Server { $name = Get-Content -Path Env:\COMPUTERNAME Get-Content -Path Env:\COMPUTERNAME | Out-File -FilePath C:\MyName.txt Get-NetAdapter -Physical $name | Out-File -FilePath C:\MyOtherName.txt } New-Server -PSComputerName CLIENT,DC

When I first wrote this example, I thought, “MyOtherName.txt will be empty.” Remember, the contents of the workflow each run as a separate command, with no shared context between them. When I ran this example, though, it worked. The computer name was indeed written to both MyName.txt and MyOtherName.txt. What gives?

Windows PowerShell actually does a lot of under-the-hood stuff to try and make sure you get the results you expect from a workflow. For example, a “normal” workflow command is written in a very specific way. WF can’t natively run just any old Windows PowerShell cmdlet. The Windows PowerShell team provides WF equivalents for a huge list of native cmdlets, so there’s often a one-to-one mapping between cmdlets and WF activities.

When you use a cmdlet that doesn’t have a corresponding activity, Windows PowerShell implicitly wraps your code within a WF InlineScript activity. That has the effect of making WF run Windows PowerShell, execute your command within Windows PowerShell and then take the results back into WF. So a lot of stuff that “shouldn’t” work will work, because Windows PowerShell hacks it together for you.

The danger here is that troubleshooting can become incredibly difficult, because you won’t always be able to see what Windows PowerShell is doing under the hood. In the case of this example, Windows PowerShell ensures that top-level variables persist throughout the workflow.

Where we’re going next

Believe it or not, you’ve already got enough to start writing basic workflows. You can have these target any computer where you’ve installed Windows PowerShell version 3 and enabled Remoting. Part of the reason for enabling Remoting is that it creates a session configuration that Windows PowerShell Workflow uses. If you’ve enabled Remoting on a computer with Windows PowerShell version 2 and then later installed version 3, you’ll want to re-run Enable-PSRemoting to create the necessary configuration.

Keep your workflows fairly simple. Run a sequence of commands and don’t do a lot of fancy maneuvers. You shouldn’t have any problems, and you’ll get to take advantage of the built-in Windows PowerShell Workflow Remoting, multi-computer targeting and other features.

Next month, I’ll start getting more complicated. I’ll look at the deep differences between a workflow and a normal Windows PowerShell script, and start exploring some of the more interesting capabilities of Windows PowerShell Workflow.

Don Jones

Don Jones is a Windows PowerShell MVP Award winner and contributing editor to TechNet Magazine. He has coauthored four books about Windows PowerShell version 3, including several free titles on creating HTML reports in Windows PowerShell and Windows PowerShell Remoting. Find them all at PowerShellBooks.com, or ask Jones your question in the discussion forums at PowerShell.org.