Azure 自动化中的子 RunbookChild runbooks in Azure Automation

在 Azure 自动化中,建议的做法之一是编写可重用、模块化且提供可由其他 Runbook 调用的离散函数的 Runbook。It is a recommended practice in Azure Automation to write reusable, modular runbooks with a discrete function that is called by other runbooks. 父 Runbook 通常会调用一个或多个子 Runbook 来执行所需的功能。A parent runbook often calls one or more child runbooks to perform required functionality. 可通过两种方式调用子 Runbook,应了解这些方法的明显差异,以确定哪种方法最适合自己的方案。There are two ways to call a child runbook, and there are distinct differences that you should understand to be able to determine which is best for your scenarios.

使用内联执行调用子 RunbookInvoking a child runbook using inline execution

若要从另一个 Runbook 调用某个内联 Runbook,请使用被调用 Runbook 的名称并提供其参数值,就像使用活动或 cmdlet 时一样。To invoke a runbook inline from another runbook, use the name of the runbook and provide values for its parameters, just like you would use an activity or a cmdlet. 同一自动化帐户中的所有 Runbook 可按此方式相互使用。All runbooks in the same Automation account are available to all others to be used in this manner. 父 Runbook 将等待子 Runbook 完成,并转移到下一行,并直接向父级返回任何输出。The parent runbook waits for the child runbook to complete before moving to the next line, and any output returns directly to the parent.

在调用某个内联 Runbook 时,它会在与父 Runbook 所在的同一个作业中运行。When you invoke a runbook inline, it runs in the same job as the parent runbook. 子 Runbook 的作业历史记录中不会提供相应的指示。There is no indication in the job history of the child runbook. 子 Runbook 发生的任何异常和任何流输出将与父级关联。Any exceptions and any stream outputs from the child runbook are associated with the parent. 此行为减少了作业数并简化了作业的跟踪和故障排除。This behavior results in fewer jobs and makes them easier to track and to troubleshoot.

发布某个 Runbook 时,必须事先发布它所调用的任何子 Runbook。When a runbook is published, any child runbooks that it calls must already be published. 原因是在编译 Runbook 时,Azure 自动化会生成与任何子 Runbook 的关联。The reason is that Azure Automation builds an association with any child runbooks when it compiles a runbook. 如果尚未发布子 Runbook,则父 Runbook 看似发布正常,但在启动时会生成异常。If the child runbooks have not already been published, the parent runbook appears to publish properly but generates an exception when it is started. 如果发生这种情况,可以重新发布父 Runbook,以正确引用子 Runbook。If this happens, you can republish the parent runbook to properly reference the child runbooks. 如果由于已创建关联而更改了任何子 Runbook,则不需重新发布父 Runbook。You do not need to republish the parent runbook if any child runbook is changed because the association has already been created.

内联调用的子 Runbook 的参数可以是任意数据类型,包括复杂对象。The parameters of a child runbook called inline can be of any data type, including complex objects. 不会进行 JSON 序列化,因为使用 Azure 门户或 Start-AzureRmAutomationRunbook cmdlet 启动 Runbook 时会进行这种序列化。There is no JSON serialization, as there is when you start the runbook using the Azure portal or with the Start-AzureRmAutomationRunbook cmdlet.

Runbook 类型Runbook types

哪些 Runbook 类型可以互相调用?Which runbook types can call each other?

  • PowerShell Runbook图形 Runbook 可以互相内联调用,两者都基于 PowerShell。A PowerShell runbook and a graphical runbook can call each other inline, as both are PowerShell-based.
  • PowerShell 工作流 Runbook 和图形 PowerShell 工作流 Runbook 可以互相内联调用,两者都基于 PowerShell 工作流。A PowerShell Workflow runbook and a graphical PowerShell Workflow runbook can call each other inline, as both are PowerShell Workflow-based.
  • PowerShell 类型和 PowerShell 工作流类型不能互相内联调用,并且必须使用 Start-AzureRmAutomationRunbookThe PowerShell types and the PowerShell Workflow types can't call each other inline, and must use Start-AzureRmAutomationRunbook.

发布顺序何时重要?When does publish order matter?

Runbook 的发布顺序仅对于 PowerShell 工作流和图形 PowerShell 工作流 Runbook 重要。The publish order of runbooks only matters for PowerShell Workflow and graphical PowerShell Workflow runbooks.

当 Runbook 在通过内联执行调用图形或 PowerShell 工作流子 Runbook 时,它会使用被调用 Runbook 的名称。When your runbook calls a graphical or PowerShell Workflow child runbook using inline execution, it uses the name of the runbook. 该名称必须以 .\\ 开头,表示脚本位于本地目录中。The name must start with .\\ to specify that the script is located in the local directory.

示例Example

以下示例将启动一个测试子 Runbook,该 Runbook 接受复杂对象、整数值和布尔值。The following example starts a test child runbook that accepts a complex object, an integer value, and a boolean value. 该子 Runbook 的输出将分配到某个变量。The output of the child runbook is assigned to a variable. 在本示例中,子 Runbook 属于 PowerShell 工作流 Runbook。In this case, the child runbook is a PowerShell Workflow runbook.

$vm = Get-AzureRmVM -ResourceGroupName "LabRG" -Name "MyVM"
$output = PSWF-ChildRunbook -VM $vm -RepeatCount 2 -Restart $true

下面是使用 PowerShell Runbook 作为子级的同一示例。Here is the same example using a PowerShell runbook as the child.

$vm = Get-AzureRmVM -ResourceGroupName "LabRG" -Name "MyVM"
$output = .\PS-ChildRunbook.ps1 -VM $vm -RepeatCount 2 -Restart $true

使用 cmdlet 启动子 RunbookStarting a child runbook using a cmdlet

Important

如果 Runbook 将 Start-AzureRmAutomationRunbook cmdlet与 Wait 参数一起使用来调用子 Runbook,并且子 Runbook 生成对象结果,则该操作可能会遇到错误。If your runbook invokes a child runbook with the Start-AzureRmAutomationRunbook cmdlet with the Wait parameter and the child runbook produces an object result, the operation might encounter an error. 若要解决此错误,请参阅使用对象输出的子 Runbook,以了解如何实现相关逻辑来轮询结果并使用 Get-AzureRmAutomationJobOutputRecord cmdlet。To work around the error, see Child runbooks with object output to learn how to implement the logic to poll for the results using the Get-AzureRmAutomationJobOutputRecord cmdlet.

可以按照使用 Windows PowerShell 启动 Runbook 中所述,使用 Start-AzureRmAutomationRunbook 来启动 Runbook。You can use Start-AzureRmAutomationRunbook to start a runbook as described in To start a runbook with Windows PowerShell. 使用此 cmdlet 的模式有两种。There are two modes of use for this cmdlet. 在第一种模式下,cmdlet 将在为子 Runbook 创建作业时返回作业 ID。In one mode, the cmdlet returns the job ID when the job is created for the child runbook. 在第二种模式(由脚本通过指定 Wait 参数启用)下,cmdlet 会等待子作业完成,并且会返回子 Runbook 的输出。In the other mode, which your script enables by specifying the Wait parameter, the cmdlet waits until the child job finishes and returns the output from the child runbook.

使用 cmdlet 启动的子 Runbook 的作业独立于父 Runbook 作业运行。The job from a child runbook started with a cmdlet runs separately from the parent runbook job. 此行为会导致比启动内联 Runbook 更多的作业,并使这些作业更难以跟踪。不过,父级可以异步启动多个子 Runbook,而无需等待每个子 Runbook 完成。This behavior results in more jobs than starting the runbook inline, and makes the jobs more difficult to track. The parent can start more than one child runbook asynchronously without waiting for each to complete. 对于内联调用子 Runbook 的这种并行执行,父 Runbook 必须使用并行关键字For this parallel execution calling the child runbooks inline, the parent runbook must use the parallel keyword.

由于时间原因,子 Runbook 的输出不会可靠地返回到父 Runbook。Child runbook output does not return to the parent runbook reliably because of timing. 另外,$VerbosePreference$WarningPreference 和其他某些变量可能不会传播到子 Runbook。In addition, variables such as $VerbosePreference, $WarningPreference, and others might not be propagated to the child runbooks. 为避免这些问题,可以将 Start-AzureRmAutomationRunbookWait 参数配合使用来将子 Runbook 作为单独的自动化作业调用。To avoid these issues, you can start the child runbooks as separate Automation jobs using Start-AzureRmAutomationRunbook with the Wait parameter. 此方法会阻止父 Runbook,直到子 Runbook 完成。This technique blocks the parent runbook until the child runbook is complete.

如果不希望父 Runbook 在等待时被阻止,则可以使用不带 Wait 参数的 Start-AzureRmAutomationRunbook 启动子 Runbook。If you don't want the parent runbook to be blocked on waiting, you can start the child runbook using Start-AzureRmAutomationRunbook without the Wait parameter. 在这种情况下,Runbook 必须使用 Get-AzureRmAutomationJob 等待作业完成。In this case, your runbook must use Get-AzureRmAutomationJob to wait for job completion. 它还必须使用 Get-AzureRmAutomationJobOutputGet-AzureRmAutomationJobOutputRecord 来检索结果。It must also use Get-AzureRmAutomationJobOutput and Get-AzureRmAutomationJobOutputRecord to retrieve the results.

使用 cmdlet 启动的子 Runbook 的参数以哈希表形式提供,如 Runbook 参数中所述。Parameters for a child runbook started with a cmdlet are provided as a hashtable, as described in Runbook parameters. 只能使用简单数据类型。Only simple data types can be used. 如果 Runbook 的参数使用复杂数据类型,则必须内联调用该 Runbook。If the runbook has a parameter with a complex data type, then it must be called inline.

将子 Runbook 作为单独作业启动时,可能会丢失订阅上下文。The subscription context might be lost when starting child runbooks as separate jobs. 为使子 Runbook 针对特定的 Azure 订阅执行 Az Rm cmdlet,子 Runbook 必须独立于父 Runbook 对此订阅进行身份验证。For the child runbook to execute Az Rm cmdlets against a specific Azure subscription, the child must authenticate to this subscription independently of the parent runbook.

如果同一自动化帐户中的作业使用多个订阅,则选择一个作业中的订阅可能也会更改当前所选的其他作业的订阅上下文。If jobs within the same Automation account work with more than one subscription, selecting a subscription in one job can change the currently selected subscription context for other jobs. 若要避免这种情况,请在每个 Runbook 的开头使用 Disable-AzureRmContextAutosave –Scope ProcessTo avoid this situation, use Disable-AzureRmContextAutosave –Scope Process at the beginning of each runbook. 此操作仅保存该 Runbook 执行的上下文。This action only saves the context to that runbook execution.

示例Example

以下示例将启动一个包含参数的子 Runbook,并将 Start-AzureRmAutomationRunbook cmdlet 与 Wait 参数配合使用来等待其完成。The following example starts a child runbook with parameters and then waits for it to complete using the Start-AzureRmAutomationRunbook cmdlet with the Wait parameter. 完成后,该示例将从子 Runbook 收集 cmdlet 输出。Once completed, the example collects cmdlet output from the child runbook. 若要使用 Start-AzureRmAutomationRunbook,脚本必须向 Azure 订阅进行身份验证。To use Start-AzureRmAutomationRunbook, the script must authenticate to your Azure subscription.

# Ensure that the runbook does not inherit an AzContext
Disable-AzureRmContextAutosave -Scope Process

# Connect to Azure with Run As account
$ServicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'

Add-AzureRmAccount `
    -EnvironmentName AzureChinaCloud `
    -ServicePrincipal `
    -TenantId $ServicePrincipalConnection.TenantId `
    -ApplicationId $ServicePrincipalConnection.ApplicationId `
    -CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint

$AzureContext = Select-AzureRmSubscription -SubscriptionId $ServicePrincipalConnection.SubscriptionID

$params = @{"VMName"="MyVM";"RepeatCount"=2;"Restart"=$true}

Start-AzureRmAutomationRunbook `
    -AutomationAccountName 'MyAutomationAccount' `
    -Name 'Test-ChildRunbook' `
    -ResourceGroupName 'LabRG' `
    -AzureRMContext $AzureContext `
    -Parameters $params -wait

子 Runbook 调用方法的比较Comparison of methods for calling a child runbook

下表汇总了从一个 Runbook 调用另一个 Runbook 的两种方式的差异。The following table summarizes the differences between the two ways to call a runbook from another runbook.

内联Inline CmdletCmdlet
作业Job 子 Runbook 在父级所在的同一个作业中运行。Child runbooks run in the same job as the parent. 为子 Runbook 创建单独的作业。A separate job is created for the child runbook.
执行Execution 父 Runbook 等待子 Runbook 完成,然后继续。Parent runbook waits for the child runbook to complete before continuing. 父 Runbook 会在子 Runbook 启动后立刻继续运行,或 父 Runbook 会等待子作业完成。Parent runbook continues immediately after child runbook is started or parent runbook waits for the child job to finish.
输出Output 父 Runbook 可以直接从子 Runbook 获取输出。Parent runbook can directly get output from child runbook. 父 Runbook 必须检索子 Runbook 作业的输出,或 父 Runbook 可以直接从子 Runbook 获取输出。Parent runbook must retrieve output from child runbook job or parent runbook can directly get output from child runbook.
parametersParameters 子 Runbook 参数的值需单独指定,并且可以使用任意数据类型。Values for the child runbook parameters are specified separately and can use any data type. 子 Runbook 参数的值必须组合成单个哈希表。Values for the child runbook parameters have to be combined into a single hashtable. 此哈希表只能包含简单数据类型、数组和利用 JSON 序列化的对象数据类型。This hashtable can only include simple, array, and object data types that use JSON serialization.
自动化帐户Automation Account 父 Runbook 只能使用同一自动化帐户中的子 Runbook。Parent runbook can only use child runbook in the same Automation account. 父 Runbook 可以使用任何自动化帐户中、同一 Azure 订阅中,甚至连接到的不同订阅中的子 Runbook。Parent runbooks can use a child runbook from any Automation account, from the same Azure subscription, and even from a different subscription to which you have a connection.
发布Publishing 在发布父 Runbook 之前必须先发布子 Runbook。Child runbook must be published before parent runbook is published. 在启动父 Runbook 之前随时可以发布子 Runbook。Child runbook is published any time before parent runbook is started.

后续步骤Next steps