Service Management Automation 中的子 Runbook

在 Service Management Automation(SMA)中,最佳做法是编写可重用的模块化 Runbook,其中包含可由其他 Runbook 使用的离散函数。 父 Runbook 通常会调用一个或多个子 Runbook 来执行所需的功能。 可通过两种方法来调用子 Runbook,每种方法各自具有显著差异,你应了解这些差异,以便可以确定最适合于各种不同方案的方法。

使用内联执行调用子 Runbook

要从另一个 runbook 内联调用 runbook,请使用 runbook 的名称,并完全按照使用活动或 cmdlet 的相同方式为其参数提供值。 相同 SMA 环境中的所有 Runbook 都可供要采用此方法使用的所有其他 Runbook 使用。 父 runbook 会等待子 runbook 完成,然后移动到下一行,并且任何输出都会直接返回给父级。

内联调用 runbook 时,它会在与父 runbook 相同的作业中运行。 子 runbook 的作业历史记录中不会存在有关其运行的指示。 来自子 runbook 的任何异常和任何流输出都会与父级关联。 这样便会使作业较少,并且可以更轻松地对它们进行跟踪和故障排除,因为子 Runbook 引发的任何异常及任何流输出都与父 runbook 的作业关联。

发布运行手册时,它调用的任何子运行手册都必须已经有一个已发布的版本。 这是因为在编译运行手册时,自动化会与任何子运行手册建立关联。 如果子 Runbook 没有已发布的版本,则父 Runbook 会看似发布正常,但是会在启动时生成异常。 如果发生这种情况,则可以重新发布父 runbook 以便正确引用子 runbook。 如果有任何子 Runbook 更改,则无需重新发布父 Runbook,因为已创建了关联。

内联调用的子 Runbook 的参数可以是任何数据类型(包括复杂对象),并且不进行 JSON 序列化 (使用管理门户或通过 Start-SmaRunbook cmdlet 启动 Runbook 时会进行这种序列化)。

Runbook 类型

Runbook 只能使用相同类型的另一个 Runbook 作为使用内联执行的子 Runbook。 这意味着 PowerShell 工作流 Runbook 不能将 PowerShell Runbook 作为使用内联执行的子级,并且 PowerShell Runbook 不能使用 PowerShell 工作流 Runbook。

使用内联执行调用 PowerShell 工作流子运行簿时,只需使用运行簿的名称。 调用 PowerShell 子 Runbook 时,必须在其名称前面加上 .\ 以指定脚本位于本地目录中。

示例

下面的示例将调用一个测试子 Runbook,该 Runbook 接受三个参数:一个复杂对象、一个整数和一个布尔值。 该子 Runbook 的输出将分配到某个变量。 在此情况下,子运行手册是一个PowerShell工作流运行手册。

$vm = Get-VM -Name "MyVM" -ComputerName "MyServer"
$output = Test-ChildRunbook -VM $vm -RepeatCount 2 -Restart $true

以下是使用 PowerShell 脚本 Runbook 作为子项的示例。

$vm = Get-VM -Name "MyVM" -ComputerName "MyServer"
$output = .\Test-ChildRunbook.ps1 -VM $vm -RepeatCount 2 -Restart $true

使用 Cmdlet 启动子 Runbook

可以使用 Start-SMARunbook cmdlet 通过 Windows PowerShell 启动 Runbook。 从 cmdlet 启动子 runbook 时,父 runbook 会在为子 runbook 创建了作业之后立即移动到下一行。 如果您需要检索来自流程文档的任何输出,则需要使用 Get-SMAJobOutput 来访问作业。

使用 cmdlet 启动的子 Runbook 作业会作为独立的作业,与父 Runbook 的作业分开运行。 这导致比内联调用工作流更多的作业,增加了工作进程服务器上的开销,并使得它们更难以跟踪。不过,父 Runbook 可以启动多个子 Runbook,而无需等待每个子 Runbook 完成。 对于内联调用子 runbook 的那种相同类型的并行执行,父 runbook 需要使用 并行关键字

使用 cmdlet 启动的子 Runbook 的参数以哈希表形式提供,如 Runbook 参数中所述。 只能使用简单数据类型,不过可以提供凭据资产的名称(如 Credentials中所述)。 如果 runbook 具有复杂数据类型的参数,则它必须进行内联调用。

下面的示例启动一个具有参数的子 runbook,然后等待它完成。 一旦完成,便由父 runbook 从作业收集其输出。

$webServer = 'https://MyServer'
$port = 9090
$runbookName = "Test-Runbook"
$params = @{"VMName"="MyVM";"RepeatCount"=2;"Restart"=$true}

$job = Start-SmaRunbook -WebServiceEndpoint $webServer -Port $port -Name $runbookName -Parameters $params

$doLoop = $true
While ($doLoop) {
   $job = Get-SmaJob -WebServiceEndpoint $webServer -Port $port -Id $job.Id
   $status = $job.Status
   $doLoop = (($status -ne "Completed") -and ($status -ne "Failed") -and ($status -ne "Suspended") -and ($status -ne "Stopped")
}

Get-SmaJobOutput -WebServiceEndpoint $webServer -Port $port -Id $job.Id -Stream Output

比较用于调用子 Runbook 的方法

下表总结了用于从另一个 runbook 调用 runbook 的两种方法之间的差异。

内联 Cmdlet (命令行工具)
作业 子 Runbook 在父级所在的同一个作业中运行。 为子 Runbook 创建单独的作业。
执行 父 runbook 等待子 runbook 完成后再继续进行。 父 runbook 在启动子 runbook 之后立即继续进行。
输出 父 runbook 可以直接从子 runbook 获取输出。 父 runbook 必须从子 runbook 作业检索输出。
参数 子 Runbook 参数的值需单独指定,并且可以使用任意数据类型。 子 Runbook 参数的值必须组合成单个哈希表,并且只能包含使用 JSON 序列化的简单、数组和对象数据类型。
发布 发布父 runbook 之前,必须先发布子 runbook。 必须在启动父 Runbook 之前的任何时间先发布子 Runbook。

后续步骤