Starting an Azure Automation Runbook on a Hybrid Worker via Azure Webhook and PowerShell

When using Runbooks in Azure Automation, we can use a Hybrid Worker Group to access local resources within that groups data center. The Hybrid Worker Groups can be targeted when starting a Azure Automation Runbook . For more on Runbooks see Starting a runbook in Azure Automation.

With an Azure Automation webhook, we can start a Runbook in Azure Automation via a HTTP POST request. This allows us to leverage external services to call a runbook. When we create a webhook against a runbook, we have to specify parameters and run settings (for running in Azure or a  Hybrid Worker Group).  For more on webhooks see Starting an Azure Automation runbook with a webhook.

In some scenarios, you may want to start the Runbook with the option to select a particular Hybrid Worker Group and pass certain parameters without necessarily being limited to the default parameters.

In this blog post, I will show you how call a webhook from PowerShell to start to runbook on Azure, then pass parameters from that runbook to one that runs on a hybrid runbook worker group.

image

Requirements

Azure Variables

Before we go into the runbook side, we need to create some assets in the Automation Account in Azure. To do this, sign into portal.azure.com, go to your Automation Account\Assets and create the following in the relevant section.

 

Name Type Description
SubscriptionID Variable Subscription ID for your Automation Account.
ResourceGroup Variable The Resource group name which your runbooks are held in.
AccountName Variable The Automation Automation account name.
Azure-Creds Credential Credentials for authenticating to your Azure Automation Resource.

 

Runbook to run on Hybrid Worker

The following example uses a PowerShell runbook which will run against the Hybrid Worker Group. The runbook is just downloading a file via bits.

Param
(
$URL,
$FileDestination
)

$BitsTransfer  = Start-BitsTransfer -Source "$($url)" -Destination "$($FileDestination)" -Asynchronous

while( ($BitsTransfer.JobState.ToString() -eq 'Transferring') -or ($BitsTransfer.JobState.ToString() -eq 'Connecting') )
{
Write-Output "State: $($BitsTransfer.JobState.ToString())"
$Process = ($BitsTransfer.BytesTransferred / $BitsTransfer.BytesTotal) * 100
Write-Output $Process '%'
Sleep 3
}
Complete-BitsTransfer -BitsJob $BitsTransfer

To use this, on the Runbooks blade in the Azure portal, save the runbook as PowerShell script called Start-FileTransfer.

Webhook Runbook to run in Azure

Because the above script needs to be run on-premise we need to create a runbook which we can call in Azure via PowerShell. To achieve this, we need to format the runbook so we can receive data from a PowerShell webhook call. To do this we use the $webhookData parameter which  will contain the data from a POST web request.

param (
[object]$WebhookData
)

if ($WebhookData -ne $null) {

# Collect properties of WebhookData
$WebhookName    =   $WebhookData.WebhookName
$WebhookHeaders =   $WebhookData.RequestHeader
$WebhookBody    =   $WebhookData.RequestBody

# Collect individual headers. Parameters converted from JSON.
$From = $WebhookHeaders.From
$HWParams = ConvertFrom-Json -InputObject $WebhookBody
#Collect Azure Automation Runbook Variables
$SubscriptionID= Get-AutomationVariable -Name 'SubscriptionID' -ErrorAction Stop
$ResourceGroupName = Get-AutomationVariable -Name 'ResourceGroup' -ErrorAction Stop
$AutomationAccountName = Get-AutomationVariable -Name 'AccountName' -ErrorAction Stop

#Create Friendly Variables
$ChildRunbookName = "$($HWParams.Runbook)"
$RunOn = "$($HWParams.HybridWorkerGroup)"
$URL = "$($HWParams.URL)"
$FileDestination = "$($HWParams.FileDestination)"
Write-Output "Runbook start request from webhook $WebhookName by $From."
Write-Output "The Hybridworker Group to run against: $($HWParams.HybridWorkerGroup)"

# Authenticate to Azure resources
$Creds = "Azure-Creds"
$AzureCreds = Get-AutomationPSCredential -Name $Creds -ErrorAction Stop
Write-Output "Signing into Azure RM as $($AzureCreds.Username)"
Login-AzureRmAccount -Credential $AzureCreds -SubscriptionId $SubscriptionId -ErrorAction Stop

#Paramaters Passed to Auutomation Runbook
$param = @{"URL"="$URL";"FileDestination"="$($FileDestination)"}

# Start the Automation Runbook
$job = Start-AzureRMAutomationRunbook -ResourceGroupName "$ResourceGroupName" –AutomationAccountName "$AutomationAccountName" –Name "$ChildRunbookName" -RunOn "$RunON" -Parameters $Param
# Determine if there is a job and if the job output is wanted or not
if ($job -eq $null) {
# No job was created, so throw an exception
throw ("No job was created for runbook: $ChildRunbookName.")
}
else {
# Job Found

# Log the started runbook’s job id for tracking
Write-Output "Started runbook: $ChildRunbookName. Job Id: $($job.JobId)"

if (-not $WaitForJobCompletion) {
# Don't wait for the job to finish, just return the job id
Write-Output "Started Job ID: $($job.JobId)"
}
else {
# Monitor the job until finish or timeout limit has been reached
$maxDateTimeout = (Get-Date).AddSeconds($JobPollingTimeoutInSeconds)
Write-Output "Max Date Timeout: $maxDateTimeout"
$doLoop = $true

while($doLoop) {
Start-Sleep -s $JobPollingIntervalInSeconds

$job = Get-AzureRMAutomationJob -Id $job.JobId -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName

if ($maxDateTimeout -lt (Get-Date)) {
# timeout limit reached so exception
$msg = "The job for runbook $ChildRunbookName did not "
$msg += "complete within the timeout limit of "
$msg += "$JobPollingTimeoutInSeconds seconds, so polling "
$msg += "for job completion was halted. The job will "
$msg += "continue running, but no job output will be returned."
throw ($msg)
}

$doLoop = (($job.Status -notmatch "Completed") `
-and ($job.Status -notmatch "Failed") `
-and ($job.Status -notmatch "Suspended") `
-and ($job.Status -notmatch "Stopped"))
}

if ($job.Status -match "Completed") {
if ($ReturnJobOutput) {
# Output
$jobout = Get-AzureRMAutomationJobOutput `
-Id $job.JobId `
-ResourceGroupName $ResourceGroupName `
-AutomationAccountName $AutomationAccountName `
-Stream Output
if ($jobout) {Write-Output "$($jobout.Summary)"}

# Error
$jobout = Get-AzureRMAutomationJobOutput `
-Id $job.JobId `
-ResourceGroupName $ResourceGroupName `
-AutomationAccountName $AutomationAccountName `
-Stream Error
if ($jobout) {Write-Error "`nSummary: $($Jobout.Summary) `nError: $($Jobout.Value.CategoryInfo)"}

# Warning
$jobout = Get-AzureRMAutomationJobOutput `
-Id $job.JobId `
-ResourceGroupName $ResourceGroupName `
-AutomationAccountName $AutomationAccountName `
-Stream Warning
if ($jobout) {Write-Warning "$($jobout.Summary)"}

# Verbose
$jobout = Get-AzureRMAutomationJobOutput `
-Id $job.JobId `
-ResourceGroupName $ResourceGroupName `
-AutomationAccountName $AutomationAccountName `
-Stream Verbose
if ($jobout) {Write-Verbose "$($jobout.Summary)"}
}
else {
# Return the job id
Write-Output $job.JobId
}
}
else {
# The job did not complete successfully, so throw an exception
$msg = "The child runbook job did not complete successfully."
$msg += "  Job Status: " + $job.Status + "."
$msg += "  Runbook: " + $ChildRunbookName + "."
$msg += "  Job Id: " + $job.JobId + "."
$msg += "  Job Exception: " + $job.Exception
throw ($msg)
}
}

Write-Output "Runbook Finished"
}
}
else {
Write-Error "Runbook can only be started from a webhook."
}

The above script will convert the data passed from the client webhook call and run a Start-AzureRMAutomationRunbook command to run the bits transfer on the Hybrid Worker Group supplied.

To use this, on the Runbooks blade in the Azure portal, save the runbook as PowerShell script called WH-Start-FileTransfer.

Creating the Webhook

Once the runbook for the webhook is created,  following procedure to create a linked webhook.

  1. From the Runbooks blade in the Azure portal, select the runbook.
  2. Click Webhook at the top of the blade to open the Add Webhook blade.
    image
  3. In the Add Webhook blade, click Create new webhook to open the Create webhook blade.
  4. Specify a Name, Expiration Date for the webhook and  leave it enabled.
  5. Copy the URL of the webhook. Note once you create the webhook, you cannot retrieve the URL again.
    image#
  6. Click Parameters and leave the parameters blank as we will be providing the parameters when calling the webhook via PowerShell.
  7. Click Create to create the webhook.

Calling the Webhook Via PowerShell

The last part to the puzzle is calling the webhook through PowerShell, this allows us to run the bits transfer from any location and run it against a Hybrid Worker Group. The below script passes the runbook details and parameters required as well as the Hybrid Worker Group to run against.

#Runbook Webhook URL
$WebhookURI = 'Enter Runbook Webhook URL'

#Runbook Name & Hybrid Worker Group
$Runbook = 'Start-FileTransfer'
$HybridWorkerGroup = "<Enter Hybrid Worker Group;"

#Parameter for related script
$URL = 'Enter file download destination'
$FileDestination = 'File destination to save to local server'
$headers = @{"From"="$($WebhookHeader)"}
$Params  = @([pscustomobject]@{Runbook="$($Runbook)";HybridWorkerGroup="$($HybridWorkerGroup)";URL="$($URL)";FileDestination="$FileDestination"})
$body = ConvertTo-Json -InputObject $Params
$response = Invoke-RestMethod -Method Post -Uri "$($WebhookURI)" -Headers $headers -Body $body
$response.JobIds

 

This method is great for not being restricted by saved webhooks parameters or where the runbook runs on, allowing you to run on different Hybrid Worker Groups via one webhook.

Tagged with:

Leave a Reply

Your email address will not be published. Required fields are marked *