Tuesday, May 19, 2015

Developing Workflows in PowerShell


Workflow Foundation is a .Net framework for defining complex processes that can span a long period of time, can be stopped and restarted where they left off, support parallel execution of tasks, and can be packaged into reusable components.  Until PowerShell 3.0, workflows could only be created in Visual Studio using C# or VB .Net.  PowerShell 3.0 added support for the creation and execution of workflows. PowerShell workflows can be executed locally or on remote machines, thereby running parallel processes across multiple machines dramatically improving performance and scalability.  In Azure, PowerShell workflows are called Runbooks and can be used for a variety of tasks.

Note:  See the bottom of this blog for information on a free presentation I am doing tomorrow night!



PowerShell makes implementing workflows intuitive but misleading.  The workflow keyword is used to define a workflow similar to defining a function but a workflow is actually quite different.  The reason is that the cmdlets in a workflow are actually translated into the Workflow Foundation language and submitted for processing.  PowerShell is not running the code, Workflow Foundation is.   

To try the code samples below, you will need to start the PowerShell ISE which can be done as follows.  Click the Start Menu, select All Programs, open the Accessories folder, then the Windows PowerShell folder and run either Windows PowerShell ISE or Windows PowerShell ISE (x86).  The x86 indicates this is the 32 bit version whereas the other is the 64 bit version.


Once in the ISE, you can paste the code samples into the script window and click on the execute button (the green arrow in the toolbar) in the toolbar as shown below to execute the samples.



Let'e try a simple example of a workflow. Consider the code below which defines a workflow called simple.


workflow simple ([string] $myparm)

{

   "Parameter is $myparm"

  

   Get-Date



   "Some activity"



   "Third activity"

}

The code above defines a workflow but to call it, we need to execute the workflow as shown below.

workflow 'test'

We should see the output to the console below.  



Parameter is test



Sunday, May 17, 2015 4:03:07 PM

Some activity

Third activity

Notice the first keyword above, workflow, which is where we would normally see the word  function.  That's all it takes to create a workflow in PowerShell.  

However, behind the scenes there is more going on.  In an effort to make it easy for PowerShell developers to migrate to workflows, Microsoft added a cmdlet translator to PowerShell which is invoked via the workflow keyword.  Anything contained in the workflow code block is submitted to a translator which converts the code into the workflow language and submits it to the workflow engine to be processed.  This means there are some differences between what is supported in functions versus workflows.  

Let’s try some code that breaks the workflow engine to see this.  Consider the code below.

workflow simplebroken ([string] $myparm)

{

   Write-Host "Parameter is $myparm"

  

   $object = New-Object PSObject



   $object | Add-Member -MemberType NoteProperty -Name MyProperty -Value 'something'



   $object.MyProperty

}



simplebroken 'test' # Runs the workflow

When we run the code above, we get a number of error messages.  Why?  The answer is that only a subset of PowerShell cmdlets are mapped to workflow equivalents and Write-Host is not one of them.  Another problem is that each statement in a workflow runs as a separate process, called an activity, so we cannot define a complex object in one line, and access it from another.  Interestingly, simple variables such as strings can be accessed by multiple lines.  In fact, the workflow can be suspended and resumed and the variable values will be restored when the workflow restarts.  Complex objects cause problems because they can not readily be serialized to disk and restored.

There is a workaround for the lack of complex object support across activities.  We can use the workflow command inlinescript which will run a scriptblock as one activity.  Therefore, the lines in the script block can see any objects created in the script.  This is shown in the code below.

workflow simpleinline ([string] $myparm)

{
  inlinescript
  {
     Write-Verbose "Parameter is $Using:myparm"
  
     $object = New-Object PSObject

     $object | Add-Member -MemberType NoteProperty -Name MyProperty -Value 'something'

     $object.MyProperty
  }
}

simpleinline 'test' –Verbose  # Calls the workflow

Above, an object is created and a property added to it which is displayed.  Since it is all in the scriptblock, there is no problem.  Also notice, Write-Verbose is supported by workflows.

Now that we have a feel for workflows, let's look at code that uses the three workflow specific commands other than inlinescript. These are sequence, parallel, and foreach -parallel. 

workflow paralleltest {

 sequence
 {
  "1"
  "2"
  "3"
 }

 parallel
 {

   for($i=1; $i -le 100; $i++){ "a" }

   for($i=1; $i -le 100; $i++){ "b" } 

   for($i=1; $i -le 100; $i++){ "c" }

 }

  $collection = "one","two","three"

  foreach -parallel ($item in $collection)
  {
   "Length is: " + $item.Length
  }

}

paralleltest  # This statement calls the workflow

The first workflow command above is sequence which instructs the workflow engine to run the statements in between the braces sequentially.  This is followed by the parallel statement that tells the workflow engine to run each statement in between the braces in parallel, i.e. concurrently.  Lastly, we see the foreach -parallel statement which iterates over a collection running the code in between the braces in parallel.  This would most likely be used to iterate over a list of machine names submitting code to run remotely on those machines.  

The possibilities with workflows are endless and in a future blog we will discuss how to suspend a workflow for any period of time and resume it having it picked up where it left off.  Yes. Workflows can retain state and we'll learn all about that next time.

Tomorrow night, Wednesday, May 20, at 6:30 PM, I will be presenting a free in-depth presentation on PowerShell Workflows entitled Workflows for the Rest of Us.  You can reserve a seat at the link below.
http://www.meetup.com/The-RI-Microsoft-BIUG/events/222490566/

Just click on the 'Join Us' link and RSVP.  The presentation is free as is pizza and soda and there will be a number of items and swag given out.  Our group also does a lot of free webinars so even if you can't make this meeting, please join so you will be kept up to date.

Thanks,

Bryan