While Service Management Automation (SMA) provides a cool web-based runbook authoring experience in the Windows Azure Pack, many folks are more comfortable using a good old-fashioned tool they’re already familiar with to write PowerShell – the Windows PowerShell ISE. While in theory it should be very easy to write SMA runbooks in the PowerShell ISE since runbooks are essentially PowerShell workflows, in reality there are a few hiccups one needs to overcome. This blog post will outline those hiccups and explain how you can overcome them to make your PowerShell ISE into a lean, mean, runbook-authoring machine. It also provides a download of the EmulatedAutomationActivities PowerShell module, which lets you use the Get-Automation* activities that were previously available only in SMA runbooks, in regular PowerShell.
Before we discuss the authoring of runbooks in the PowerShell ISE, let’s talk about the basic process you’ll want to follow when authoring your runbooks outside of SMA’s own runbook authoring tool.
For a new runbook, follows these steps:
- Write a PowerShell workflow in the ISE.
- Test the workflow on the local machine.
- When fully tested, save the workflow as a .ps1 file.
- Import the .ps1 file into SMA as a runbook.
- Test the runbook you just imported in the SMA authoring page, using the Test button.
- When fully tested, publish the runbook in the SMA authoring page using the Publish button.
If you are attempting to modify an existing SMA runbook rather than write a new one from scratch, the steps looks like this:
- Put the runbook you want to modify into edit mode using the SMA authoring pane.
- Copy / paste the runbook from the SMA runbook editor to a blank window in the PowerShell ISE to edit is as a PowerShell workflow
- Update the PowerShell workflow as needed in the PowerShell ISE.
- Test the workflow on the local machine.
- When fully tested, copy / paste the workflow from the ISE back into the SMA runbook editor, overwriting the old runbook draft with this updated runbook draft.
- Test the updated runbook you just copied into SMA in the authoring page using the Test button.
- When fully tested, publish the runbook in the SMA authoring page using the Publish button.
Since this post is all about using a familiar PowerShell environment over the Automation portal in the Windows Azure Pack, let’s quickly cover how you can take the above steps from the PowerShell ISE, without using the SMA portal at all. This is possible via the cmdlets of the SMA PowerShell module:
- To import a new runbook into SMA as a draft, use the Import-SmaRunbook cmdlet
- To publish the draft of a runbook in SMA, use the Publish-SmaRunbook cmdlet
- To get the existing PowerShell contents of a runbook in SMA (either draft or published version), use the Get-SmaRunbookDefinition cmdlet
- To updated the draft contents of a runbook in SMA, use the Edit-SmaRunbook cmdlet
- To start a runbook in SMA, use the Start-SmaRunbook cmdlet
- To get the status of a runbook job you started in SMA, use the Get-SmaJob cmdlet
- To get the output of a runbook job you started in SMA, use the Get-SmaJobOutput cmdlet
One thing to note is there is currently no way to kick off a test of an SMA runbook draft using the SMA PowerShell cmdlets – you cannot start a runbook’s draft version from the cmdlets, only its published version. So if you want to kick off a test of a runbook you wrote in the ISE and then transferred into SMA, to make sure it works correctly in SMA, you need to publish the runbook in SMA, and then start it.
Making It Work
There are a few things you will need to do / understand to fully take advantage of the PowerShell ISE as an SMA runbook authoring tool.
1: Starting a runbook
The first thing to be aware of is a tiny detail that people tend to forget which can cause some headaches. This detail is the difference between running a workflow as a runbook in the SMA authoring experience versus running it as a PowerShell workflow in the PowerShell ISE. On the SMA authoring page, running a runbook is as simple as hitting the Test button. This will compile and start the runbook. However, in the PowerShell ISE, there is no equivalent “compile and run” button. You must first compile the workflow by defining its definition in PowerShell, and then run it by typing out the workflow name.
When you want to run the workflow in the ISE, first compile the workflow by running the script. This can be done by hitting the green “play” button, as shown below. Then you can start the workflow by calling the workflow name directly in the PowerShell console attached to the ISE. From below, you can see two PowerShell commands are executed. The first defines the PowerShell workflow, easily done by clicking the “play” button, and the second runs the workflow:
Note As you continually update and test the workflow, remember to click the “play” button before each test to run the script, causing a recompile of the workflow to include your latest changes. If you run the workflow without recompiling it, you will still be running the version of the workflow that was last compiled.
As a best practice, make sure the script containing your workflow contains only the workflow, and no commands outside the workflow (comments above the workflow are fine, though). This is because when you import the script into SMA as a runbook, only the workflow for the runbook can be present in the script for import to be successful.
2: Working with child runbooks
Let’s say you want to write a runbook in the ISE that relies on some child (nested) runbooks. These could be new child runbooks you wish to create, also in the ISE, or existing runbooks in SMA that you want to leverage. You may even have child runbooks that call other child runbooks, forming a large dependency hierarchy.
The best practice here if you want to write these runbooks in the ISE is to start from the innermost child runbook, and work your way outwards until you are at your overall parent runbook, which you would start in order to kick off all child runbooks you wrote, and any child runbooks those child runbooks call, etc. This way, you are writing runbooks in an order where the dependent (child) runbooks of any runbook you write already exist.
In terms of the details, there’s a number of different scenarios for writing parent / child runbooks in the ISE, depending on whether you are calling the nested runbooks synchronously or asynchronously, and whether the nested runbooks already exist in SMA or not. Below I’ll outline the important aspects of each scenario and how you can handle them.
If you want to start a child runbook asynchronously from a runbook you are writing in the ISE, and the child exists and has been published in SMA already, you should use the Start-SmaRunbook SMA PowerShell cmdlet to start the child runbook via the SMA web service. The SMA PowerShell module can be installed locally from the SMA installer, allowing you to use the Start-SmaRunbook cmdlet in your PowerShell workflows in the ISE. Because the SMA PowerShell module ships as an out of box integration module in SMA, it is already available for use in SMA runbooks, so using this cmdlet in a workflow in the ISE and then moving that workflow into SMA as a runbook will “just work.”
Here’s what this scenario looks like in the ISE and in SMA. The workflow Say-HelloToJohn calls the child workflow Say-Hello. As you can see below the workflow can work in SMA as a runbook with no changes from the ISE version:
SMA Authoring Pane:
If you want to start a child runbook asynchronously from a runbook you are writing in the ISE, and the child does not exist in SMA already, the scenario is very similar to the scenario just discussed above. Simply follow the best practice and write the child runbook first in the ISE, then import it into SMA and publish it. Then use Start-SmaRunbook in the parent runbook as discussed above.
If you want to start a child runbook synchronously from a runbook you are writing in the ISE, and the child does not exist in SMA already, simply follow the best practice and write the child runbook first in the ISE. When the child workflow is done, start working on the parent workflow. While you can’t call SMA runbooks synchronously from workflows in the PowerShell ISE, you can call workflows synchronously from workflows in the ISE. So, to accomplish having a runbook you are writing in the ISE call another runbook synchronously in the ISE, define and compile that child runbook as a workflow in the ISE, and call it inline from the parent. Calling a runbook synchronously from a runbook uses the same syntax as calling a workflow synchronously from a workflow, so this will allow you to test calling one workflow from another synchronously in the ISE, and then import these workflows as runbooks into SMA and call one synchronously from the other without having to make any changes to the runbooks’ definition.
Here’s what this scenario looks like in the ISE and in SMA. The workflow Say-HelloToJohn calls the workflow Say-Hello, shown previously in a screenshot above, as a child workflow, synchronously. Since calling workflows from workflows will only work if the child workflow is already defined and compiled when the parent workflow is compiled, make sure to always define and compile the child workflow before the parent.
Note If you ever have to make an update to the child workflow and wish to test this updated child workflow as part of the parent workflow, remember to recompile the child workflow, and then the parent workflow, so your latest changes to the child workflow are included when run from the parent workflow.
Once moved to SMA, make sure the child runbook is published before attempting to run or publish the parent runbook which calls this child runbook. As you can see below the workflows can work in SMA as runbooks with no changes from the ISE versions:
SMA Authoring Pane:
If you want to start a child runbook synchronously from a runbook you are writing in the ISE, and the child exists in SMA already, simply copy the child runbook’s definition to a PowerShell workflow in the ISE, and then follow the scenario right above this one. If you end up needing to make any changes to the child workflow you copied into the ISE in order to get it to work correctly with the parent workflow you are writing in the ISE, make sure to update the child runbook as well with this new code and publish it in SMA before attempting to run the parent workflow as a runbook in SMA.
3: Using SMA-only activities
SMA ships with a set of activities useful for interacting with SMA assets from within runbooks. However, these activities do not exist outside of the SMA runbook execution environment. This means there is no way to take advantage of these activities from the PowerShell ISE. These activities are:
Since SMA runbooks are meant to rely heavily on SMA assets to reference important information that shouldn’t be hard coded within runbooks, having access to these activities during runbook authoring is very important. As you can see from below, since these activities don’t exist in the PowerShell ISE, runbook authoring can be challenging to do in the ISE if you want to follow best practices of relying on SMA assets. The workflow being shown below calls the workflow Say-Hello, shown previously in a screenshot above, as a child runbook.
The variable our runbook relies on. It contains the value “Scott”:
The runbook we are writing, working correctly in the SMA authoring experience:
The runbook we are writing, failing to compile in the PowerShell ISE, because the Get-AutomationVariable activity is not available outside of SMA:
So, how can we get around this obstacle and write runbooks that depend on SMA assets from the PowerShell ISE? Well, as you probably know, we have this great set of cmdlets in the SMA PowerShell module that let you, among other things, get SMA assets, set SMA assets, and start SMA runbooks. Wouldn’t it be great if we could somehow take advantage of these cmdlets to implement non-SMA versions of the SMA-only activities for use in the runbooks we write in the ISE? For example, could the ISE implementation of the Get-AutomationVariable SMA-only activity internally use Start-SmaRunbook to start a runbook that outputs the value of an SMA variable, and then use Get-SmaJobOutput to grab that output?
It turns out, yes, this is possible, and we’ve made it very simple for you to do. We’ve written a PowerShell module, “EmulatedAutomationActivities,” which contains an ISE-friendly implementation of all the SMA-only activities, using the SMA cmdlets behind the scenes. It covers all the SMA-only activities:
Note The EmulatedAutomationActivities module should not be installed on any SMA Runbook Worker host. If it is installed, it could cause runbooks running on that worker to fail because the worker won’t know whether to use the real Get-Automation* activities or the emulated ones when it runs runbooks. This means that if you want to take advantage of the SMA-only activities in the PowerShell ISE, you can only write ISE runbooks on a host that is not an SMA Runbook Worker.
In order to take advantage of the EmulatedAutomationActivities module, all you need to do is:
- Install the SMA PowerShell module on the host you want to use the EmulatedAutomationActivities PowerShell module from
- Download the EmulatedAutomationActivities module and Get-AutomationAsset runbook from here
- Unzip the download
- Import the Get-AutomationAsset runbook into SMA, and publish it
- Open up EmulatedAutomationActivitiesInner.psm1 and modify $SmaWebServiceDetails to contain the correct info to connect to your SMA web service:
6. Put the contents of EmulatedAutomationActivities under C:\Users\USERNAME\Documents\WindowsPowerShell\Modules, like so:
7. Tell PowerShell to allow this module to be loaded even though you downloaded it from the Internet:
Now just open up the PowerShell ISE, and kick back, relax, and take advantage of SMA-only activities in the runbooks you author. Here’s the same Say-HelloToMyLittleFriend runbook that didn’t work in the ISE before, now working thanks to the EmulatedAutomationActivities PowerShell module!
Now, there is one caveat about the EmulatedAutomationActivities module you should know. Internally, each of the Get-Automation* activities it contains works by kicking off the Get-AutomationAsset runbook. This runbook takes in an asset name and type, and outputs the asset’s value in serialized form. The Get-Automation* activities then read in this output and deserialize it back into a value, giving you access to the values of SMA assets in your ISE runbooks.
The fact that this runbook outputs the serialized values of SMA assets, combined with the fact that this output is in plain text, means that when this runbook runs it is possible for someone with access to SMA to see the values of “secret” SMA assets, whether they be credentials, encrypted variables, or encrypted connection fields, in the output of Get-AutomationAsset’s jobs. For this reason, as a best practice, runbooks you write that leverage the EmulatedAutomationActivities module to work in the ISE should only be used to grab non-encrypted assets, or encrypted “test” SMA assets (those that only provide access to “test” systems or contain “fake” secret information).
This problem does not exist for SMA certificate assets, however, because while they are stored encrypted in SMA, Get-AutomationAsset will only return an SMA certificate’s thumbprint, not any secret information such as the private key. EmulatedAutomationActivities then attempts to grab the cert with this thumbprint from the local certificate store on the machine where it is installed. So, in order for Get-AutomationCertificate to work for your SMA certificate assets, make sure the certificates you want to utilize in runbooks being authored in the ISE are stored in the certificate store on the local machine.
As Aleksandar points out in the comments, another important point I forgot to mention is that SMA runbooks running in the PowerShell ISE run in the context of the current user who started the workflow. In SMA, runbooks run under the context of the service account that the runbook worker service (rbsvc) runs as. This can lead to discrepancies between a runbook running in the ISE and in SMA if your runbook depends on the account the runbook is running as. For example, if your runbook remotes into a virtual machine that your runbook worker service account has access to but the user writing the runbook in the ISE does not, the runbook will fail in the ISE but work in SMA. The opposite is possible too – you remote into a virtual machine that your current ISE user has access to but not the runbook worker, then the runbook will fail in SMA but not the ISE.
There are a few ways to work around this, for example write runbooks in the ISE as the runbook worker service account (log in as this account, then open ISE), but the best practice is to make sure your runbooks don't need to be under the context of a certain user to work. The way to do this is to make sure any activities you perform that require some higher access level are placed within an InlineScript activity, and the InlineScript is run with the -PSCredential parameter specifying the credential of the user this InlineScript needs to run as to perform this action. That way, the account the runbook worker service runs as won't matter.
If you’re one of those folks who loves the PowerShell ISE, you should now have the knowledge and tools you’ll need to successfully write and test your SMA runbooks there. Best of all, you won’t have to sacrifice any runbook functionality just because you’re writing runbooks in the ISE, such as nested runbooks or access to SMA assets.
Until next time,
Happy automating (from the PowerShell ISE!)