When working with Azure Automation Runbooks, it is quite common that one runbook needs to trigger another runbook and wait for the result before continuing the process.
The cmdlet Start-AzAutomationRunbook provides the parameter -Wait, which at first glance seems to solve exactly this problem. The command waits until the child runbook finishes. However, there is a major limitation: when using -Wait, the command does not return the JobId of the executed runbook.
This creates a problem. Without the JobId, it becomes difficult to reliably identify the job that was just started. A possible workaround would be retrieving the latest job from the automation account, but that approach has no guarantee that the returned job actually belongs to the runbook execution that was triggered.
A more reliable solution is to start the runbook without using the -Wait parameter. This way the command immediately returns the JobId. With that identifier available, the job can be monitored directly until it reaches a terminal state such as Completed, Failed, Stopped, or Suspended.
The advantage of this approach is that the automation can track the real status of the runbook. If the runbook fails, the caller receives the actual Failed state instead of assuming success. Additionally, it becomes possible to retrieve the runbook output, which can then be used for further processing.
Connecting to Azure Automation
$AzureContext = (Connect-AzAccount -Identity).contextWrite-Output "Successfully connected to Azure using the system-assigned managed identity."$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext
Function to wait for the runbook job
function Wait-ChildRunbookJob { param( [string] $ResourceGroupName, [string] $AutomationAccountName, [guid] $JobId, [int] $PollSeconds = 5, [int] $TimeoutSeconds = 3600, $DefaultProfile ) $terminal = @('Completed','Failed','Stopped','Suspended') $deadline = (Get-Date).AddSeconds($TimeoutSeconds) while ($true) { if ((Get-Date) -gt $deadline) { throw "Timeout waiting for job $JobId after $TimeoutSeconds seconds." } $job = Get-AzAutomationJob ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName ` -Id $JobId ` -DefaultProfile $DefaultProfile if ($terminal -contains $job.Status) { return $job } Start-Sleep -Seconds $PollSeconds }}
Function to retrieve runbook output streams
function Get-ChildRunbookStreams { param( [string] $ResourceGroupName, [string] $AutomationAccountName, [guid] $JobId, [string] $Stream = 'Any', $DefaultProfile ) $headers = Get-AzAutomationJobOutput ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName ` -Id $JobId ` -Stream $Stream ` -DefaultProfile $DefaultProfile $records = $headers | Get-AzAutomationJobOutputRecord ` -ResourceGroupName $ResourceGroupName ` -AutomationAccountName $AutomationAccountName ` -JobId $JobId ` -DefaultProfile $DefaultProfile $records}
Starting the child runbook
$job = Start-AzAutomationRunbook ` -ResourceGroupName 'RG-Automation-Test' ` -AutomationAccountName 'aa-automation-test' ` -Name $RunbookName ` -RunOn 'HybridWorker01' ` -DefaultProfile $AzureContextWrite-Output "JobId is $($job.JobId)"
Waiting for completion
$job = Wait-ChildRunbookJob ` -ResourceGroupName "RG-Automation-Test" ` -AutomationAccountName "aa-automation-test" ` -JobId $job.JobId ` -PollSeconds 5 ` -TimeoutSeconds 3600 ` -DefaultProfile $AzureContext
Retrieving the output
$jobout = Get-ChildRunbookStreams ` -ResourceGroupName "RG-Automation-Test" ` -AutomationAccountName "aa-automation-test" ` -JobId $job.JobId ` -Stream 'Any' ` -DefaultProfile $AzureContext$status = $job.Statusif($status -eq 'Completed'){ Write-Output "The job completed successfully"}elseif($status -eq 'Failed'){ Write-Output "The job failed"}
Summary
By starting the runbook without the -Wait parameter and monitoring the JobId manually, it becomes possible to reliably track the runbook execution. This approach provides several advantages:
- The JobId of the child runbook is always available
- The exact runbook status can be retrieved
- Failures can be handled correctly
- The runbook output can be reused for further processing
This approach is especially useful when building larger automation scenarios where runbooks depend on each other and require reliable status handling.