Runbook
This article walks you through the creation of a Runbook in Azure Automation. We'll start with creating a simple Runbook to Start VM that we'll test and publish. Then, we'll walk you through how to create the Runbook for Stop VM to actually manage Azure resources.
What is Runbook?
Automation of PowerShell scripts execution can be achieved through implementation of Runbook in Azure Portal. Runbook can be scheduled as a job to atomized PowerShell script execution. Also, Webhook can be created on Runbook. Webhook can be used as a http endpoint to trigger Runbook from application.
Through Runbook, most of resources management process automation is possible in Azure portal, i.e., creation, deletion, start, stop of VM/ Vnet/NSG/Public IP/NIC, etc.
Cost optimization can be achieved by automatically spinning up and spinning off VMs through Runbook execution when VMs are not in use.
Some organizations required VMs up on some specific dates on month to achieve some activities to finish. Rest of the month VM are not in use, at that time VM can be stopped(deallocated)/deleted. Whenever VM is required or first request received from first user, at that time VM can be automatically created/started dynamically through Runbook Webhook implementation. Will see this use case in this article.
Runbook vs PowerShell
Azure automation is supported using two options, Windows PowerShell and workflow which is known as a Runbook. Even Runbook internally uses PowerShell scripts. But the major benefit is Runbook itself executes in Azure portal context. This execution is secure and less error prone.
To execute PowerShell script in Azure from local machine, the user has to authenticate through either certificate publish or Azure login cmdlets. The user has to provide username, password and subscription id.
Where Runbook executes with service account on Azure portal. Service account can be created through Credential object in automation account and co-administrator role level user in active directory assigned to this service account.
In PowerShell script, “Verbose” switch can be specified with cmdlets for user confirmation, whereas in Runbook, you can’t specify “Verbose” switch and couldn’t make user interactive confirmation while execution.
Wherever confirmation is required from user in PowerShell script execution in Runbook, “Force” switch can be specified to override execution of cmdlets in Runbook.
Create Runbook
Steps to create Runbook and execute in Azure Portal:
Create new automation account
Click on New in upper right corner on Azure new portal and type automation in textbox. It will populate Azure automation account resource as per below.
Select Automation option. It will redirect to the below screen.
Click on Create button. It will redirect to the below screen.
Provide Automation account name, select subscription, resource group in which you want to create automation account. Location will be populated by default based on resource group selection. Select Yes on Create Azure Run as Account. Once automation account will be created, it will be shown on resources list blade as below:
Clicking on Automation account name shows all resources available to create as well as a list of already created resources.
Add Credential Validation
To execute scripts whether it is a PowerShell script, Workflow, DSC or Runbook, it requires credential to execute scripts.
Here, we will use Azure active directory Service Principal user. First of all, create user in Azure active directory from Azure classic portal. Then, assign Co-administrator role to this user at subscription level.
Clicking on Assets blade on the above screen shows the below screen.
Clicking on Credentials blade shows the below screen where we can add Service principal user which we have created in Active Directory in classic portal.
Clicking on Add a credential button shows the below screen. From this screen, Service Principal user which created in classic portal under active directory needs to be added. Same details which were used when creating user like username, password need to be added here.
Click on Create button will create Service Principal user under Credential resources in Assets.
Runbook 1: Start VM
Click on Runbooks tab from the above screen. It shows the below screen to create new Runbook.
Click on Add a Runbook icon to add new Runbook. It shows new screen as below to add Runbook. Click Quick Create.
Enter Runbook name “VMStart”, select Runbook type as “PowerShell” from dropdown and click Create button. It creates and open new window for Runbook draft to add scripts as below.
Add below code in Edit PowerShell Runbook window. Click on Save button from upper bar and save the Runbook.
param(
[parameter(Mandatory=$false)]
[String] $AzureCredentialName = "Use *Default Automation Credential* Asset",
[parameter(Mandatory=$false)]
[String] $AzureSubscriptionName = "Use *Default Azure Subscription* Variable Value",
[parameter(Mandatory=$false)]
[String] $VMName = "YourVMName",
[parameter(Mandatory=$false)]
[String] $ResourceGroupName = "YourResourceGroupName"
)
# Main Runbook content
try
{
# Retrieve subscription name from variable asset if not specified
if($AzureSubscriptionName -eq "Use *Default Azure Subscription* Variable Value")
{
$AzureSubscriptionName = Get-AutomationVariable -Name "Default Azure Subscription"
if($AzureSubscriptionName.length -gt 0)
{
Write-Output "Specified subscription name/ID: [$AzureSubscriptionName]"
}
else
{
throw "No subscription name was specified, and no variable asset
with name 'Default Azure Subscription' was found.
Either specify an Azure subscription name or define the default using a variable setting"
}
}
# Retrieve credential
write-output "Specified credential asset name: [$AzureCredentialName]"
if($AzureCredentialName -eq "Use *Default Automation Credential* asset")
{
# By default, look for "Default Automation Credential" asset
$azureCredential = Get-AutomationPSCredential -Name "Default Automation Credential"
if($azureCredential -ne $null)
{
Write-Output "Attempting to authenticate as: [$($azureCredential.UserName)]"
}
else
{
throw "No automation credential name was specified,
and no credential asset with name 'Default Automation Credential' was found.
Either specify a stored credential name or define the default using a credential asset"
}
}
else
{
# A different credential name was specified, attempt to load it
$azureCredential = Get-AutomationPSCredential -Name $AzureCredentialName
if($azureCredential -eq $null)
{
throw "Failed to get credential with name [$AzureCredentialName]"
}
}
write-output "Test: [$azureCredential]"
# Connect to Azure using credential asset (classic API)
$account = Add-AzureAccount -Credential $azureCredential
# Check for returned userID, indicating successful authentication
if(Get-AzureAccount -Name $azureCredential.UserName)
{
Write-Output "Successfully authenticated as user: [$($azureCredential.UserName)]"
}
else
{
throw "Authentication failed for credential [$($azureCredential.UserName)].
Ensure a valid Azure Active Directory user account is specified which is configured
as a co-administrator (using classic portal) and subscription owner (modern portal)
on the target subscription. Verify you can log into the Azure portal using these credentials."
}
# Validate subscription
$subscriptions = @(Get-AzureSubscription | where {$_.SubscriptionName
-eq $AzureSubscriptionName -or $_.SubscriptionId -eq $AzureSubscriptionName})
if($subscriptions.Count -eq 1)
{
# Set working subscription
$targetSubscription = $subscriptions | select -First 1
$targetSubscription | Select-AzureSubscription
# Connect via Azure Resource Manager
$resourceManagerContext = Add-AzureRmAccount -Credential $azureCredential
-SubscriptionId $targetSubscription.SubscriptionId
$currentSubscription = Get-AzureSubscription -Current
Write-Output "Working against subscription: $($currentSubscription.SubscriptionName)
($($currentSubscription.SubscriptionId))"
}
else
{
if($subscription.Count -eq 0)
{
throw "No accessible subscription found with name or ID [$AzureSubscriptionName].
Check the Runbook parameters and ensure user is a co-administrator
on the target subscription."
}
elseif($subscriptions.Count -gt 1)
{
throw "More than one accessible subscription found with name or
ID [$AzureSubscriptionName]. Please ensure your subscription names are unique,
or specify the ID instead"
}
}
Write-Output "[($VMName)]: Starting VM."
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName
}
catch
{
$errorMessage = $_.Exception.Message
throw "Unexpected exception: $errorMessage"
}
finally
{
Write-Output "Runbook finished (Duration: $(("{0:hh\:mm\:ss}"
-f ((Get-Date).ToUniversalTime() - $currentTime))))"
}
Test Runbook
To test Runbook, click on Test Pane icon. It will open new window as shown below.
Click on Start button. See result. If Runbook executes successfully, close the Test Pane window.
Publish Runbook
Now click on Publish icon in Edit PowerShell Runbook window from the below screen. It will publish Runbook.
VMStart Runbook is successfully published as below:
Execute Runbook
This Runbook is ready to execute. Click on Start icon from the below screen. It will execute Runbook.
This Runbook can be scheduled as a job. Also, Webhook can be created as an http endpoint to trigger Runbook from outside application which we will see in future articles.
Runbook 2: Stop VM
Click on Runbooks tab from the below Automation Account screen.
It shows the below screen to create new Runbook.
Click on Add a Runbook icon to add new Runbook. It shows new screen to add Runbook. Click Quick Create.
Enter Runbook name “VMStop”, select Runbook type as “PowerShell” from dropdown and click Create button. It creates and opens a new window for Runbook draft to add scripts as below.
Add the below code in Edit PowerShell Runbook window.
param(
[parameter(Mandatory=$false)]
[String] $AzureCredentialName = "Use *Default Automation Credential* Asset",
[parameter(Mandatory=$false)]
[String] $AzureSubscriptionName = "Use *Default Azure Subscription* Variable Value",
[parameter(Mandatory=$false)]
[String] $VMName = "YourVMName",
[parameter(Mandatory=$false)]
[String] $ResourceGroupName = "YourResourceGroupName"
)
# Main Runbook content
try
{
# Retrieve subscription name from variable asset if not specified
if($AzureSubscriptionName -eq "Use *Default Azure Subscription* Variable Value")
{
$AzureSubscriptionName = Get-AutomationVariable -Name "Default Azure Subscription"
if($AzureSubscriptionName.length -gt 0)
{
Write-Output "Specified subscription name/ID: [$AzureSubscriptionName]"
}
else
{
throw "No subscription name was specified, and no variable asset with name
'Default Azure Subscription' was found.
Either specify an Azure subscription name or define the default using a variable setting"
}
}
# Retrieve credential
write-output "Specified credential asset name: [$AzureCredentialName]"
if($AzureCredentialName -eq "Use *Default Automation Credential* asset")
{
# By default, look for "Default Automation Credential" asset
$azureCredential = Get-AutomationPSCredential -Name "Default Automation Credential"
if($azureCredential -ne $null)
{
Write-Output "Attempting to authenticate as: [$($azureCredential.UserName)]"
}
else
{
throw "No automation credential name was specified,
and no credential asset with name 'Default Automation Credential' was found.
Either specify a stored credential name or define the default using a credential asset"
}
}
else
{
# A different credential name was specified, attempt to load it
$azureCredential = Get-AutomationPSCredential -Name $AzureCredentialName
if($azureCredential -eq $null)
{
throw "Failed to get credential with name [$AzureCredentialName]"
}
}
write-output "Test: [$azureCredential]"
# Connect to Azure using credential asset (classic API)
$account = Add-AzureAccount -Credential $azureCredential
# Check for returned userID, indicating successful authentication
if(Get-AzureAccount -Name $azureCredential.UserName)
{
Write-Output "Successfully authenticated as user: [$($azureCredential.UserName)]"
}
else
{
throw "Authentication failed for credential [$($azureCredential.UserName)].
Ensure a valid Azure Active Directory user account is specified which is configured
as a co-administrator (using classic portal) and subscription owner (modern portal)
on the target subscription. Verify you can log into the Azure portal using these credentials."
}
# Validate subscription
$subscriptions = @(Get-AzureSubscription | where {$_.SubscriptionName
-eq $AzureSubscriptionName -or $_.SubscriptionId -eq $AzureSubscriptionName})
if($subscriptions.Count -eq 1)
{
# Set working subscription
$targetSubscription = $subscriptions | select -First 1
$targetSubscription | Select-AzureSubscription
# Connect via Azure Resource Manager
$resourceManagerContext = Add-AzureRmAccount
-Credential $azureCredential -SubscriptionId $targetSubscription.SubscriptionId
$currentSubscription = Get-AzureSubscription -Current
Write-Output "Working against subscription:
$($currentSubscription.SubscriptionName) ($($currentSubscription.SubscriptionId))"
}
else
{
if($subscription.Count -eq 0)
{
throw "No accessible subscription found with name or ID [$AzureSubscriptionName].
Check the runbook parameters and ensure user is a co-administrator
on the target subscription."
}
elseif($subscriptions.Count -gt 1)
{
throw "More than one accessible subscription found with name or ID [$AzureSubscriptionName].
Please ensure your subscription names are unique, or specify the ID instead"
}
}
Write-Output "[($VMName)]: Stopping VM."
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName
}
catch
{
$errorMessage = $_.Exception.Message
throw "Unexpected exception: $errorMessage"
}
finally
{
Write-Output "Runbook finished
(Duration: $(("{0:hh\:mm\:ss}" -f ((Get-Date).ToUniversalTime() - $currentTime))))"
}
This “VMStop
” Runbook can be Tested, Published and Executed same as steps mentioned above for Runbook-1 “VMStart
”.
Summary
So, we have seen one of the most important features of Azure Automation is Runbook. This is a reusable component that can be used for automation of Azure resources management. Since it executes on Azure environment context with service principal user, it is very safe and secure in point of security context compared to PowerShell script execution from remote environment. This feature enables us to manage the Azure resources efficiently.
References
History
- 9th September, 2016: Initial version