Quick Tips and Tricks for Runbook Writing

Quick Tips and Tricks for Runbook Writing

 


Introduction

This article outlines tips for writing runbooks in Service Management Automation and Azure Automation.

Most of these tips apply to both services. If the tip doesn’t apply to both, the tip will explicitly call out SMA or Azure Automation. When you see the term Automation used, the tip refers to both. These tips do not go into detail about why we suggest you follow this guidance. For more detail on PowerShell Workflow and runbook, look at our runbook authoring documentation and PowerShell Workflow introduction guide.

Also check out this PowerShell Workflow Gotchas wiki that highlights some of the most frequently problems that SMA and Azure Automation users run into. 

 


General Guidance

DO

  • use verbs from the approved verbs list when naming your runbooks.
  • give the same name to .ps1 files and the workflow they contain.
  • follow the naming convention for PowerShell cmdlets when you name your runbooks / PowerShell workflows:  <ApprovedVerb>-<Noun>.
  • test your workflow in Automation, especially if you authored it in a local environment first.
  • explicitly define which parameters are and are not mandatory.

CONSIDER

  • using an InlineScript block if you're going to use the pipeline.

AVOID

  • strongly typing runbook parameters which are not primitive types.
  • interacting with or depending upon local server resources on the Runbook Worker if you are using SMA.
  • relying on any resources you yourself have not copied to the runbook host in Azure Automation. If you need to use a file, checkpoint then copy it to the host to ensure it will be where you expect it.
  • using the pipeline (i.e. chaining cmdlets with the “|” character) in PowerShell Workflow, unless you understand that a complex object is not being passed through the pipeline.
  • creating runbooks that are expected to execute for an excessively long time period. If you want a monitor runbook to run all the time, start a new instance of it by calling Start-SMARunbook or Start-AzureAutomationRunbook before the job completes.

DO NOT

  • use switch parameters on PowerShell workflows (use a Boolean parameter type instead).
  • use positional parameters to cmdlets.
  • use interactive commands or commands that expect a console.  For example: Write-Host 

 


Comments

Prefix your runbooks with an explanatory comment block following MSFT guidance

Make sure to include the following labels:

  • .SYNOPSIS – provide an quick overview of the workflow’s functionality
  • .DESCRIPTION – provide a more in depth description of the workflow’s functionality
  • .PARAMETER – provide a parameter section for each of your parameters and include the parameter name, type and brief description
  • .EXAMPLE – provide an example of using your workflow
  • .NOTES – add any additional that might aid understanding of the workflow

CONSIDER

  • using write-verbose statements instead of / in addition to comments to provide instrumentation for troubleshooting.
  • using #region and #endregion tags to organize long scripts.

 


Using InlineScript

DO

  • use the same variable name when bringing values inside an InlineScript block with the $using directive.
  • use an InlineScript block if you need to call a method on an object returned by a cmdlet.
  • be aware that Automation modules are not available if you are connecting to local host with an InlineScript block (unless they are explicitly installed on the local host).

CONSIDER

  • passing in your verbose/error action preferences when executing an inline script on a remote host or locally with alternate credentials.
      Example: 

     $VerbosePreference = [System.Management.Automation.ActionPreference]$Using:VerbosePreference  

      $ErrorActionPreference = [System.Management.Automation.ActionPreference]$Using:ErrorActionPreference

  • placing all $using directives at the top of an InlineScript block.

AVOID

  • passing complex/large objects (e.g. large hash tables) to InlineScripts or using them as return values from an InlineScript block.
  • writing entire workflows inside an InlineScript block.
  • passing large amounts of data (greater than 5 MB) to an InlineScript via the $using Directive.

DO NOT

  • specify credentials to an InlineScript block without also specifying a computer name (even if it is localhost).

 


Parallel Execution

CONSIDER

  • using Start-SmaRunbook or Start-AzureAutomationRunbook to do "parallel" invocations

AVOID

  • parallel execution unless tasks to be executed in parallel are independent of each other.

 


Checkpoints

DO

  • use checkpoints to save state at crucial points of your runbook.
  • ensure that workflows can safely restart from a checkpoint if interrupted.
  • retrieve credentials again from the Automation asset store after a checkpoint.

CONSIDER

  • creating a checkpoint after activities that should not be repeated (i.e. actions that are not idempotent).
  • creating a checkpoint before activities that are susceptible to failure.
  • creating a checkpoint after long-running or expensive activities that should not repeated due to cost.
  • setting variables to $null before creating a checkpoint if they contain a large amount of data that does not need to be persisted.

AVOID

  • using checkpoints that require a large amount of data (5 MB) to be persisted to the database.

 


Logging

DO

  • log messages about workflow progress and state using the cmdlets Write-Progress and Write-Verbose
  • use the Runbook Configuration page to turn on Verbose or Progress streams to help debug a production runbook
  • use the Write-Verbose cmdlet for a higher level of detail
  • disable verbose/progress logging when done troubleshooting or developing a runbook.

CONSIDER

  • including Write-Verbose statements to log values retrieved from the Automation asset store. Except values that should not be stored in plain text!!!!
  • log a start and stop message at the beginning/end of each workflow/function.

AVOID

  • enabling the “Log Progress” setting.
  • enabling Debug/Verbose logging in a Production environment unless troubleshooting an issue.

DO NOT

  • use Write-Debug
  • use the Write-Object cmdlet to log debug messages

 


Local Testing and Debugging

CONSIDER

  • using the Emulated Automation Activities module to enable local testing and debugging.
  • reading about local runbook authoring.

 


Error Handling

CONSIDER

  • using $ErrorActionPreference = "Stop" or $ErrorActionPreference = "Suspend" for runbooks that should not continue to run if they hit an error
  • using try catch and notifying the admin via email if there is an error or exception in a business critical runbook 
  • using the following pattern to log non-terminating errors encountered in a workflow.
    Write-Error -Message $_.Message -ErrorAction Continue
  • using cmdlets to get job output filtered in a human readable and sortable format:
     $JobOutput = Get-SmaJobOutput -Id $JobId -WebServiceEndpoint $WebServiceEndpoint

      OR

      $JobOutput = Get-AzureAutomationJob –Id $JobId –Account $MyAccount

  • creating a common function or runbook to handle error routing

 


Variables

DO

  • use variables in the Automation asset store for values that are expected to change between environments.

CONSIDER

  • loading all values from the Automation asset store at the beginning of your runbook.
  • using CredSSP for authentication when invoking an InlineScript on localhost in SMA.

AVOID

  • using “magic strings” or unexplained, hard-coded values in runbooks.

DO NOT

  • store any secrets (credentials, certificates, etc.) anywhere in plain text. Use the asset store instead.

 


Monitors

DO

  • separate monitor runbooks and user-interface specific functionality (e.g. fetching or updating information in SharePoint) from runbooks designed to actually complete automated tasks.

CONSIDER

  • consolidating monitors to conserve runbook worker capacity if you are using SMA.

 


PowerShell Modules

DO

  • install modules in the SMA environment using the documented process. See the Importing A Module section on TechNet or install the module on every runbook worker.
  • define connections for any modules that communicate with external systems.

 


Modularity

DO

  • define any functions within the workflow definition.
  • treat functions as if they were InlineScript blocks.
  • use try/catch statements where necessary.

CONSIDER

  • encapsulating common code
    • within a function if it will be called only within the current workflow.
    • in a separate workflow if it will be called by many different workflows and it contains business logic (e.g. business rules governing creation of an AD group).
    • in a PowerShell module if it will be called by many different workflows and it does not contain business logic (e.g. functions for creating Incidents in Remedy).
  • breaking apart lengthy workflows into logical components.

Sort by: Published Date | Most Recent | Most Useful
Comments
  • Beth, suggestion to put the emphasis on the >content< not on the do's and don't keywords themselves,

  • Sorry, added content back in again, while editing. (Pretty interesting stuff!) Feel free to kick the content again...

  • Thanks Peter!  The new formatting does help highlight the material.  Appreciate the updates!

  • Hey guys -- great stuff. Thanks for the effort. It makes it much easier to catch up to best practices when learning. ;-)

  • Thanks for article. It is useful. However, I didn't get one point. Why one should not use 'switch parameters'?[Do NOT use switch parameters on PowerShell workflows (use a Boolean parameter type instead]. Do you mind giving details?

    Regards.

  • Ohh, is it because switch parameter is not primitive type (couldn't edit my previous comment)? I thought as long as  "complex type" objects are not very large, just used as pure data (or, on other words just contains data properties) which can serialized/de-serialized it should be ok (as long as one doesn't expect to invoke methods on complex types) - or am I missing something?

    Regards..

  • We put switch as a "do not" because there are syntax differences in PS Workflow which leads to user error.  Perhaps this is a little strong and we should move this to "Avoid" as switch statements will still work.  For more info, Jim wrote a good blog explaining how to use switch statements in SMA: www.powershellmagazine.com/.../using-powershell-switch-vs-boolean-parameters-in-sma-runbooks. PowerShell's docs also have a little blurb on this: technet.microsoft.com/.../dn151046.aspx

    Also, you are right about complex objects.   You can use the properties as these can be serialized/deserialized.  This is probably the biggest point of confusion for our users as they move to PS Workflow from PowerShell which is why we warn users about using the pipeline with complex objects.  

  • We've found that even when leveraging the above considerations we have a considerable compilation issue.  We use SMA to automate various responses to SCOM alerts.  

    What I dont understand:  Why does SMA need to recompile the same runbook everytime it executes?  If the runbook hasnt been edited since the last time it has run it should simply re-execute unless it doesnt not exist ont he worker that is running it.

    That being said, since we are living in a world where we have to compile each time we run the same runbook, why is the compilation directory not configurable? It would make sense to give a setup option to point to a compilation volume such as a RAM drive or something with high IO capabilities.  We've resorted to creating a symbolic link fromt he programdata folder to a higher IO drive for the sandboxes working directory as well as moving the temp/temp folders for the service account that stores the xml files post compilation.

    The root issue is the grossly inefficient method in which compiling.  Nothing should be redone unless something has changes or it is the first time the runbook is executing on the worker.

Page 1 of 1 (8 items)