Summary: Windows PowerShell MVP and Honorary Scripting Guy Richard Siddaway talks about design considerations for Windows PowerShell workflows.

Microsoft Scripting Guy, Ed Wilson, is here. Today, we have the seventh article in the most excellent Richard Siddaway workflow series. 

Note The first article, PowerShell Workflows: The Basics, introduced the basic concepts of Windows PowerShell workflow. The second article, PowerShell Workflows: Restrictions, discussed the restrictions encountered with working with Windows PowerShell workflows. The third article was PowerShell Workflows: Nesting. The fourth article talked about PowerShell Workflows: Job Engine. The fifth article talked about PowerShell Workflows: Restarting the Computer. Next, was PowerShell Workflow: Using Parameters. You should read these articles before getting into today’s article.

Take it away, Richard …

The first big question you need to ask yourself is: “Should this be a workflow or a normal Windows PowerShell script?”

My fellow MVP Don Jones produced an excellent review of when you should use workflows:

To summarize Don’s conclusions, you should use workflows when:

  • You need to interrupt and restart tasks.
  • You need to checkpoint the task (persistence).
  • You have a mixture of sequential and parallel tasks.

 Some of the other potential reasons for using a workflow include:

  • You need to perform a long-running task that combines multiple steps in a sequence.
  • You need to perform a task that runs on multiple devices.
  • You need to perform a long-running task that is asynchronous.
  • You need to perform a long-running task that is parallelizable.

In reality, these requirements can be met by Windows PowerShell scripts or background Jobs. One of the essentials for being regarded as an expert in a technology is being able to state when it shouldn’t be used, so don’t be afraid to say no to using a workflow!

Parallelization needs to be considered as having two aspects:

  1. Simultaneously running the same tasks on a number of machines.
  2. Simultaneously running a number of tasks on a single machine.

In the first case, you could use Jobs or workflows. In the second case, you are definitely in workflow territory. There is a grey area. Imagine the case when you need to run a task on a large scale, or in high availability environments, that potentially requires throttling and connection pooling. This situation may be best suited to a Windows PowerShell Job or a workflow. There is no definitive answer either way. I know of organizations that have run Windows PowerShell Jobs that touched thousands of machines. Workflows are still too new for us to have a body of evidence to produce guidelines—if you’ve run large-scale workflows, I’d be interested in hearing your experiences, if you can share them.

One last thought before we start to look at some examples—even given that you could use a Windows PowerShell Job—there is nothing wrong with using a workflow to get experience. The only way to learn these techniques is to use them.

Let’s have a look at some examples. One common scenario is to add a registry key to a number of remote computers. Many organizations have a heterogeneous environment. I’ll simulate that by using these machines.

Machine

Operating system

Windows PowerShell version

W12SUS

Windows Server 2012

Windows PowerShell 3.0

Server02

Windows Server 2012

Windows PowerShell 3.0

WebR201

Windows Server 2008 R2

Windows PowerShell 2.0

Win7test

Windows 7

Windows PowerShell 3.0

Creating a registry key and value is a job for WMI—you didn’t think I wouldn’t touch on it, did you? One of my machines uses Windows PowerShell 2.0, so I need to use the WMI cmdlets rather than the CIM cmdlets from Windows PowerShell 3.0, because the default connection for CIM cmdlets is WSMAN, but it has to be WSMAN v3.

Adding the key involves these steps:

$hklm =  2147483650

$key = "SOFTWARE\HSGworkflowDEMO"

Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key

You need these extra steps to add a value:

$value = "AreYouThere"

$data = "Yes"

Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value

In case you are wondering about the order of the parameters, I checked this with Get-CimClass:

$class = Get-CimClass -ClassName StdRegProv

$class.CimClassMethods["SetStringValue"]

$class.CimClassMethods["SetStringValue"].Parameters

This is what was returned:

Name        CimType Qualifiers

----        ------- ----------

hDefKey      UInt32 {ID, IN}

sSubKeyName  String {ID, IN}

sValue       String {ID, in}

sValueName   String {ID, in}

If you look at the documentation, it states the sValueName should occur before sValue, which makes sense, but Invoke-WmiMethod has an issue with parameters and seems to expect them in alphabetical order! If in doubt, use the order that Get-CimClass reports.

This demonstrates what is, probably, the most important point regarding the creation of workflows: test your code outside of the workflow. If you know your code works, it makes testing the workflow easier. Using this for a local machine is a simple script. If you want to run it remotely, you have a couple options:

  1. Use the –ComputerName parameter with Invoke-WmiMethod for each call.
  2. Wrap the commands in a script block and run remotely through Invoke-Command.

In either case, you can use the –AsJob parameter.

We’ll go with option 2.

$sb = {

$hklm =  2147483650

$key = "SOFTWARE\HSGworkflowDEMO"

Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key

$value = "AreYouThere"

$data = "Yes"

Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value

}

 Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb

This could be run as a Windows PowerShell Job by adding the –AsJob parameter, which changes the last line to the following:

Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb -AsJob

As a side note, I noticed that the commands on machines with Windows PowerShell 3.0 executed more quickly than the machine with Windows PowerShell 2.0.

To turn this into a workflow involves changing the code to look like this:

workflow new-regkey {

$hklm =  2147483650

$key = "SOFTWARE\HSGworkflowDEMO"

Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key 

$value = "AreYouThere"

$data = "Yes"

Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value

}

And we run the workflow by using the –PSComputerName parameter:

new-regkey -PSComputerName server02, w12sus, win7test, webr201

So far, we have a simple task that could be accomplished in a number of ways. Let’s complicate things a bit. Your task becomes:

  • Create a registry key:  HKLM:\SOFTWARE\HSGworkflowDEMO
  • Create three values in that key and populate each with a given value:
    • AreYouThere = Yes
    • AreWeThereYet = No
    • PowerShell = 1

This gives you a mixture of parallel and sequential tasks. You have to create the key before the values, but you can create the values in parallel. You could code this as a Windows PowerShell script, and it would work perfectly but sequentially. Using a workflow means you can do things in parallel, which may be more efficient. One solution to creating a workflow to solve this problem looks like this:

workflow new-regkey {

$hklm =  2147483650

$key = "SOFTWARE\HSGworkflowDEMO"

Invoke-WmiMethod -Class StdRegProv -Name CreateKey -ArgumentList $hklm, $key

parallel {

 sequence {

  $value = "AreYouThere"

  $data = "Yes"

  Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value

 } # end of sequence

 sequence {

  $value = "PowerShell"

  $data = 1

  Invoke-WmiMethod -Class StdRegProv -Name SetDwordValue -ArgumentList $hklm, $key, $value, $data

 } # end of sequence

 sequence {

  $value = "AreWeThereYet"

  $data = "No"

  Invoke-WmiMethod -Class StdRegProv -Name SetStringValue -ArgumentList $hklm, $key, $data, $value

 }# end of sequence

}# end of parallel

}

Run the workflow:

new-regkey -PSComputerName server02, w12sus, win7test, webr201

Notice the order of arguments changes for Invoke-WmiMethod in the second sequence block. One of the joys of WMI. I really like the way you can use the –PSComputername parameter in the workflow, and it automatically passes the computer names to the workflow activities.

The workflow breaks down like this:

  • Sequentially:
    • Create the registry key
    • In parallel create three registry values—two strings and one integer
      • The creation of each value consists of three sequential steps

This is where the fun, headaches, and skill come into designing your workflows—deciding what can run in parallel, what has to run sequentially, what variables are needed, and identifying any scope issues.

As with any major piece of work, I recommend sitting down and designing your workflow before you start coding. I covered how I go about creating a script to solve a problem in my commentary on the 2012 Scripting Games.

For workflows, your decision making needs to cover:

  • What tasks is the workflow performing?
  • In what order do those tasks occur?
  • What can be performed in parallel?
  • Do I need any InLineScript blocks?
  • What variables do I need and where are they defined?
    • What is the impact of workflow scope?
  • Does the workflow run against remote computers?
    • Does it run on the local machine and access remote computers or run through remoting so that it is running on the remote computer?
    • Where do I define the computer name parameters—workflow or activity or cmdlet?
  • What do I want returned by the workflow?
  • Is there a computer restart involved in the workflow?
  • Do I need to checkpoint the workflow?
    • If so, how often?
  • Do I need to store output data outside the workflow?
  • Will the workflow run as a Job?

You’ve seen how to perform these tasks in previous workflows. How the pieces go together depends on the problem you are trying to solve.

In case you were wondering how to remove the registry keys you’ve created:

$sb = {

$hklm =  2147483650

$key = "SOFTWARE\HSGworkflowDEMO"

Invoke-WmiMethod -Class StdRegProv -Name DeleteKey -ArgumentList $hklm, $key

}

Invoke-Command -ComputerName server02, w12sus, win7test, webr201 -ScriptBlock $sb

Deleting the key removes the key, any sub-keys, and any values.

This installment has been a bit wordier than the others, but normal service will be resumed next time when you get a big workflow to consider, which incorporates a lot of what we’ve covered in the series.

~Richard

Thank you, Richard. This series is most excellent, and I really appreciate you taking the time to share your knowledge with the Windows PowerShell scripting community.

Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy