Windows PowerShell: PowerShell scripts versus PowerShell workflows
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.
Workflows look and feel a lot like a Windows PowerShell function or script, but they’re not. Their similarity is only skin-deep, and it may not even be all the way through the skin.
You have to remember that Windows PowerShell has to translate workflows into a totally separate technology—Windows Workflow Foundation (WF). That means you can only do things you can duplicate in WF. Your code will run in an entirely different kind of environment that has its own rules and restrictions. In fact, the differences between a workflow and a “normal” script can be significant.
One runspace versus many
In a normal script, everything in the script runs in a single runspace, with a single scope hierarchy. A runspace is roughly equivalent to a Windows PowerShell process. If you think of a Windows PowerShell console window, that’s a single runspace. That means everything is the same, consistent and persistent within that runspace.
Variables, commands, drives and everything else all start one way. They stay the same unless you change them. Within that runspace, any changes you make “stick” for the duration of that process.
In a workflow, every activity—every command, inline script block and so on—can have its own runspace. That means if you make a change in one, it might not be visible in any others. Setting a variable in one part of your workflow might not make any change in another part of the workflow, unless you take special steps to ensure otherwise.
As you saw in last month’s article, if you define a variable at the top level of the workflow, it exists throughout the workflow (the system takes steps to make sure this is true). If a command within the workflow creates a variable, that variable won’t be available to the rest of the workflow.
This means module use is also different. Importing a module at one point doesn’t necessarily make commands available at a later point. You need to take a lot more care, because a single workflow can essentially span multiple independent scopes.
There are a number of syntax differences within a workflow, some of which I’ve pointed out in previous articles in this series:
- You can’t use positional parameters. You must spell out every command parameter. If you’re used to running Dir C:\Windows, you’ll need to learn Get-ChildItem –Path C:\Windows instead. You can still use aliases (such as Dir) or truncated parameter names (such as –Comput for –ComputerName).
- Workflows can have parameters, but they can only include letters, numbers, the underscore and the hyphen in their names. That’s different from normal Windows PowerShell script rules.
- You can’t import a module into the workflow session. In fact, commands can’t really change the current session and have any effect on subsequent commands. If a workflow needs to use a module, you need to use the –PSRequiredModules activity parameter.
- For the InlineScript activity and commands that have workflow activity implementations, you get a bunch of extra command parameters, including the –PSRequiredModules parameter mentioned previously.
- You can’t run methods of objects in a workflow, unless you do so within an inline script block. The object must be produced within the inline script block in order for the method to work.
- You can’t dot-source scripts.
- You can’t use the “&” invocation operator.
- Switch constructs must include the –CaseSensitive parameter. The workflow equivalent of the Switch construct is natively case-sensitive. Switch statements must use constants. You can’t use comparison operators, regular expressions, file references or script blocks. Basically, try to avoid Switch constructs.
- Break and Continue statements aren’t allowed.
- Only PSDrives added by Windows PowerShell core providers—file system, registry, certificate store, environment, function, variable and WS-Management—are valid. To use a PSDrive created by a module, run the activity with a –PSRequiredModules parameter and specify the module name.
Yeah, that’s a lot of differences. If you’re a careful Windows PowerShell programmer, you’ll run up against fewer of these, such as naming your parameters. You’ll still encounter differences you forgot until you become really familiar with writing workflows.
Windows PowerShell Workflow isn’t all bad-news differences—in fact, it gives you a ton of functionality for free. Every workflow gains built-in parameters, including:
- –AsJob runs the workflow as a background job. You can give it a job name by using –JobName.
- –PSComputerName runs the workflow on the designated computer or computers, using Windows PowerShell remoting.
- –PSCredential and a variety of related parameters let you specify alternate authentication details.
- –PSPort and other connection-related parameters let you specify alternate connectivity details for the remoting component of workflow.
Notice a number of these parameters start with –PS? That’s called a namespace. You should avoid creating your own parameters that also start with –PS. If a future version of Windows PowerShell adds new parameters, they’ll likely start with –PS. If you generally avoid that prefix you’ll avoid collisions with your own parameter names.
Not worse, not better, but different
The practical upshot here is that workflows aren’t Windows PowerShell scripts. They’re different. They have some differences that can make your life easier. Some other differences can require a bit more work from you. Knowing the differences can help you more quickly start writing effective workflows.
Don Jones is a Windows PowerShell MVP Award recipient, and a contributing editor to TechNet Magazine*. He has coauthored four books about Windows PowerShell version 3, including free ones on Windows PowerShell remoting and creating HTML reports in Windows PowerShell. Find them all at PowerShellBooks.com, or ask Jones questions in the discussion forums at PowerShell.org.*