Summary: Richard Siddaway introduces you to using the Windows PowerShell job engine with your Windows PowerShell workflows.

Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the fifth in a series of posts that, hopefully, will shine the spotlight on Windows PowerShell jobs, remind people of their capabilities, and encourage their greater adoption. The full series comprises:

  1. Introduction to PowerShell Jobs
  2. WMI and CIM Jobs
  3. Remote Jobs
  4. Scheduled Jobs
  5. Jobs and Workflows (this post)
  6. Job Processes
  7. Jobs in the Enterprise

The focus on this series has been on Windows PowerShell jobs, including learning about the core job cmdlets, using the
–AsJob parameter, running jobs on remote machines, and figuring out how scheduled jobs work. Today, we are going to look at using the Windows PowerShell job engine with Windows PowerShell workflows.

Workflows are another piece of the Windows PowerShell technology, which (as with Windows PowerShell jobs) is underused. Workflows have a reputation for being difficult to work with and understand. If you’ve not experimented with workflows, I recommend that you read this series of Hey,Scripting Guy! Blog posts that I wrote in 2013:

1. PowerShell Workflows: The Basics  
Introduces workflows, key concepts, and keywords.

2. PowerShell Workflows: Restrictions
Discusses cmdlets that are not available as workflow activities, using in-line script, and using variables.

3. PowerShell Workflows: Nesting
Investigates how Windows PowerShell functions and Windows PowerShell workflows can be used inside other workflows.

4. PowerShell Workflow: Job Engine
Investigates suspending, resuming, checkpoints, and recovery.

5. PowerShell Workflows: Restarting the Computer
Investigates how workflows can survive a reboot.

6. PowerShell Workflows: Using Parameters
Investigates parameters that are available to workflows and activities, the options for connecting to remote computers, and the workflow cmdlets.

7. PowerShell Workflows: Design Considerations
Investigates design considerations for Windows PowerShell workflows.

8. PowerShell Workflows: A Practical Example
Pulls together the various strands of the series and presents the development of a workflow.

In particular, you should read post 4 about workflows and the Windows PowerShell job engine. That post looked at things from the workflow point of view. Today we’ll look at things from the job engine’s perspective.

Let’s start with a simple workflow:

workflow mysimpleworkflow

{

   Get-Process

mysimpleworkflow

This produces a list of processes that are running on the computer. It’s important to note that in a workflow, you aren’t dealing with a Windows PowerShell cmdlet, but rather, a workflow activity that functions in a similar way to the cmdlet of the same name.

If you look at the syntax of the workflow:

£> Get-Command mysimpleworkflow -Syntax

mysimpleworkflow [<WorkflowCommonParameters>] [<CommonParameters>]

It would have been nice if I could list the WorkflowCommonParameters, but there are a lot of them. You can read about them in the Help file about_WorkflowCommonParameters. If you read the Help file (and I recommend reading all of the workflow-related Help files), you will see that –AsJob is the first common parameter and –JobName is the second.

What about the workflow activities? Can we run those as a job? If you look at another Help file, about_ActivityCommonParameters, you’ll see that there aren’t any job-related parameters for workflow activities. We’ll come back to this in a while.

What happens when we run our workflow as a job?

Image of command output

The workflow was run as a job:

mysimpleworkflow -AsJob -JobName wftest

I previously dot-sourced the Windows PowerShell script that contains the workflow. A job (Id 6) is started. This time, it’s of type PSWorkflowJob. You can use the standard job cmdlets Get-Job, Receive-Job, and Remove-Job as shown in the screenshot. Apart from the type, the workflow job is behaving as a standard Windows PowerShell job. Isn’t consistency lovely? Makes our job so much easier.

You may remember that in Part 1 of this series, I mentioned that the Suspend-Job and Resume-Job cmdlets can only be used with workflow jobs. This is how you use them…

Start by creating a new workflow.

workflow mysuspenableworkflow

{

   Start-Sleep -Seconds 10

   Suspend-Workflow

   Get-Process

}

The workflow will sleep for 10 seconds and then suspend itself. When it resumes, it calls the Get-Process activity as in our previous example.

Image of command output

Dot-source and run the workflow. It sleeps for 10 seconds and then suspends. When the workflow suspends itself, a job is created in a suspended state. Notice that the workflow was started without the –AsJob parameter. Suspending a workflow will create the job. The type is still PSWorkflowJob.

You use the Resume-Job cmdlet to get the job running again. In Windows PowerShell 4.0, resuming a suspended job shows the output in the screenshot with the job’s State set to Running. In Windows PowerShell  3.0, when you used Resume-Job, the State was still shown as Suspended, and you had to use Get-Job to see the true state. After the job has completed, you can view the data and remove it as normal.

There’s one really clever feature of suspending a workflow job: You can access it in a different Windows PowerShell session.  Run the workflow again until the job suspends. When you see the message that the job has suspended, close your Windows PowerShell session.

Yep, that’s right. Just go ahead and shut it down.

Open a new Windows PowerShell session (with elevated privileges) and run Get-Job. Your suspended job will be visible if you’re using Windows PowerShell 4.0. (In Windows PowerShell 3.0, you have to import the PSWorkflow module first to be able to see the suspended jobs). You can resume the job and proceed.

What happens if you use the –AsJob parameter on a workflow that’s going to suspend?

Image of command output

Start the workflow, but this time start it as a job:

mysuspenableworkflow -AsJob -JobName suspendtest

You immediately get a running job that suspends itself after the appropriate amount of time. You can resume the job and proceed as before.

You can also suspend long running jobs from outside the job. Workflows are designed for long running tasks. You can simulate that by using a long sleep interval. This work flow will run for a while before it shows any output:

workflow mylongworkflow

{

   Start-Sleep -Seconds 60

   Checkpoint-Workflow

   Get-Process

}

In this case, we want to start the workflow as a job so that we can suspend it at will.

Image of command output

Suspend the job. Your job goes into a state of Suspending. This means that it will run until it hits the CheckPoint-Workflow activity which saves a copy of the job’s state to disk and finally suspends the job.

If you are suspending the workflow job from inside the workflow, use the Suspend-Workflow activity.  If you are going to suspend the workflow job manually, ensure that you have CheckPoint-Workflow at suitable points in your workflow so that the workflow can create a checkpoint and suspend.

Resume-Job and the other cmdlets work as expected. You could resume the workflow job in a different Windows PowerShell session if required.

We’ve discussed running workflows as jobs. But what about running jobs inside workflows? This will start a job inside a workflow, and then run the workflow:

workflow myjobflow

{

   Start-Job -ScriptBlock{Get-Process}

}

Image of command output

The workflow starts, and you can see that it shows a job is created. But if you try Get-Job,nothing is returned. The reason is that workflows aren’t run by your Windows PowerShell session. They are handed off to the workflow engine to run in a different process. That process shuts down when the workflow finishes, and you lose the job. I don’t really think there is any advantage to running jobs inside workflows because you have to handle checking that the job is complete, and then return any data from the job while the workflow is still running.

The best strategy is to run the workflow as a job. Then you get the best of both worlds.

That’s it for today. Tomorrow you’ll learn about the processes under which different job types run. Bye for now.

~Richard

Thanks, Richard. Looking forward to the final posts in this series.

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