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:
If you are attempting to modify an existing SMA runbook rather than write a new one from scratch, the steps looks like this:
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:
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:
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:
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:
Unblock-File C:\Users\USERNAME\Documents\WindowsPowerShell\Modules\EmulatedAutomationActivities\EmulatedAutomationActivities.psm1Unblock-File C:\Users\USERNAME\Documents\WindowsPowerShell\Modules\EmulatedAutomationActivities\EmulatedAutomationActivitiesInner.psm1
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!)
"6. Put the contents of EmulatedAutomationActivities under C:\Windows\System32\WindowsPowerShell\v1.0\Modules\EmulatedAutomationActivities"When we deal with our own modules, this is not the best practice advice. That path should be used only for system modules. Our own and downloaded modules should go in C:\Users\USERNAME\Documents\WindowsPowerShell\Modules folder.Also, a very important thing hasn’t been mentioned. When we author and test our SMA runbooks in PowerShell ISE, we need to be aware that they are executed in a context of the current user. SMA runbooks executed from a portal are not.
Thanks Aleksandar. I have updated the blog post based on your feedback.
Just to add to what Aleksandar said, you are really giving the wrong advice by suggesting people put modules in the Windows\System32 folder. That is a very strict no-no, and goes directly against PowerShell best practices. Seriously, just don't do it. The proper folders to recommend are as follows:1. Documents\WindowsPowerShell\Modules: use this for modules that you want available only to the current user.2. Program Files\WindowsPowerShell\Modules: use this for modules that you want available for all users.For the latter, on PowerShell 4 and later, your modules will automatically be discovered properly by PowerShell since that folder is part of the PSModulePath environment variable. On PowerShell 3, however, you must also perform one additional step if you have not done so already, which is to add Program Files\WindowsPowerShell\Modules to your PSModulePath environment variable.Don't recommend using the Windows\System32\WindowsPowerShell\v1.0\Modules folder at all, since that folder is simply not there for you to use.
Hi Kirk, Just updated the post to remove all trace of the System32 PS modules folder. Thanks for the feedback.
I would like to develop a Runbook for Azure Automation. Is this article implying that the only way to write/debug an Azure Automation Runbook is to install SMA locally? I don't want to use SMA, so why do I need to install it?
How do I write/test/debug Runbooks for Microsoft Azure Automation, using the ISE, without installing SMA?
Microsoft MVP: PowerShell
This guide is for SMA only. In the future we will be publishing a similar guide for Azure Automation. See
http://social.msdn.microsoft.com/Forums/windowsazure/en-US/8de3c565-7fa0-49b6-b5e6-1b0a586883da/any-tips-on-how-to-develop-for-azure-automation-without-actually-relying-on-the-service?forum=azureautomation for more details.
Thanks for this module. It worked perfectly on my Windows 8.1 machines, But I had to modify EmulatedAutomationActivities.psm1 to make it work on Win 7 (PowerShell v3) because PowerShell ISE is complaining about using positional parameters in PS Workflow.
So I changed $cred creation line from
$Cred = New-Object System.Management.Automation.PSCredential($Val.Username, $SecurePassword)
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Val.Username, $SecurePassword