了解 Azure 自动化的 PowerShell 工作流Learn PowerShell Workflow for Azure Automation

Azure 自动化中的 runbook 实现为 Windows PowerShell 工作流,即使用 Windows Workflow Foundation 的 Windows PowerShell 脚本。Runbooks in Azure Automation are implemented as Windows PowerShell workflows, Windows PowerShell scripts that use Windows Workflow Foundation. 工作流是一系列经过编程的连接步骤,会执行长期运行的任务,或是需要在多个设备或托管节点之间协调多个步骤。A workflow is a sequence of programmed, connected steps that perform long-running tasks or require the coordination of multiple steps across multiple devices or managed nodes.

尽管工作流是使用 Windows PowerShell 语法编写的并通过 Windows PowerShell 启动,但它由 Windows Workflow Foundation 进行处理。While a workflow is written with Windows PowerShell syntax and launched by Windows PowerShell, it is processed by Windows Workflow Foundation. 与标准脚本相比,工作流的好处包括能够同时执行针对多台设备的操作,以及能够从故障中自动恢复。The benefits of a workflow over a normal script include simultaneous performance of an action against multiple devices and automatic recovery from failures.

备注

PowerShell 工作流脚本类似于 Windows PowerShell 脚本,但包括一些可能会让新用户产生混淆的重大差异。A PowerShell Workflow script is very similar to a Windows PowerShell script but has some significant differences that can be confusing to a new user. 因此,建议仅在需要使用检查点时,才使用 PowerShell 工作流编写 runbook。Therefore, we recommend that you write your runbooks using PowerShell Workflow only if you need to use checkpoints.

有关本文中主题的完整详细信息,请参阅 Windows PowerShell 工作流入门For complete details of the topics in this article, see Getting Started with Windows PowerShell Workflow.

使用 Workflow 关键字Use Workflow keyword

将 PowerShell 脚本转换为 PowerShell 工作流的第一步,是使用 Workflow 关键字将其括起来。The first step to converting a PowerShell script to a PowerShell workflow is enclosing it with the Workflow keyword. 工作流以 Workflow 关键字开头,后接括在大括号中的脚本正文。A workflow starts with the Workflow keyword followed by the body of the script enclosed in braces. 工作流名称跟在 Workflow 关键字之后,如以下语法中所示:The name of the workflow follows the Workflow keyword as shown in the following syntax:

Workflow Test-Workflow
{
    <Commands>
}

工作流名称与自动化 Runbook 的名称匹配。The name of the workflow must match the name of the Automation runbook. 如果正在导入某个 Runbook,其文件名必须与工作流名称匹配,并且必须以 .ps1 结尾。If the runbook is being imported, then the file name must match the workflow name and must end in .ps1.

要将参数添加到工作流,请使用 Param 关键字,与使用脚本时相同。To add parameters to the workflow, use the Param keyword just as you would in a script.

了解 PowerShell 工作流代码与 PowerShell 脚本代码之间的差异Learn differences between PowerShell Workflow code and PowerShell script code

除了几个重大更改以外,PowerShell 工作流代码看起来几乎与 PowerShell 脚本代码完全相同。PowerShell Workflow code looks almost identical to PowerShell script code except for a few significant changes. 以下各部分介绍要使 PowerShell 脚本能够在工作流中运行所需进行的更改。The following sections describe changes that you need to make to a PowerShell script for it to run in a workflow.

活动Activities

活动是按顺序执行的工作流中的特定任务。An activity is a specific task in a workflow that is performed in a sequence. Windows PowerShell 工作流在运行工作流时,会自动将许多 Windows PowerShell cmdlet 转换为活动。Windows PowerShell Workflow automatically converts many of the Windows PowerShell cmdlets to activities when it runs a workflow. 在 Runbook 中指定其中的某个 cmdlet 时,相应的活动由 Windows Workflow Foundation 运行。When you specify one of these cmdlets in your runbook, the corresponding activity is run by Windows Workflow Foundation.

如果 cmdlet 没有相应的活动,Windows PowerShell 工作流会自动在 InlineScript 活动中运行该 cmdlet。If a cmdlet has no corresponding activity, Windows PowerShell Workflow automatically runs the cmdlet in an InlineScript activity. 某些 cmdlet 已被排除,不能在工作流中使用,除非显式将它们包含在 InlineScript 块中。Some cmdlets are excluded and can't be used in a workflow unless you explicitly include them in an InlineScript block. 有关详细信息,请参阅在脚本工作流中使用活动For more information, see Using Activities in Script Workflows.

工作流活动共享一组公用参数来配置其操作。Workflow activities share a set of common parameters to configure their operation. 请参阅 about_WorkflowCommonParametersSee about_WorkflowCommonParameters.

位置参数Positional parameters

无法针对工作流中的活动和 cmdlet 使用位置参数。You can't use positional parameters with activities and cmdlets in a workflow. 因此,必须使用参数名称。Therefore, you must use parameter names. 考虑下面的代码,它可以获取所有正在运行的服务:Consider the following code that gets all running services:

Get-Service | Where-Object {$_.Status -eq "Running"}

如果尝试在工作流中运行此代码,将收到一条类似 Parameter set cannot be resolved using the specified named parameters. 的消息。要更正此问题,请提供参数名称,如以下示例中所示:If you try to run this code in a workflow, you receive a message like Parameter set cannot be resolved using the specified named parameters. To correct for this issue, provide the parameter name, as in the following example:

Workflow Get-RunningServices
{
    Get-Service | Where-Object -FilterScript {$_.Status -eq "Running"}
}

反序列化的对象Deserialized objects

工作流中的对象已反序列化,这意味着其属性仍然可用,但其方法不可用。Objects in workflows are deserialized, meaning that their properties are still available, but not their methods. 例如,请考虑以下 PowerShell 代码,它使用 Service 对象的 Stop 方法停止服务。For example, consider the following PowerShell code, which stops a service using the Stop method of the Service object.

$Service = Get-Service -Name MyService
$Service.Stop()

如果尝试在工作流中运行此代码,你将收到错误消息,指出 Method invocation is not supported in a Windows PowerShell Workflow.If you try to run this in a workflow, you receive an error saying Method invocation is not supported in a Windows PowerShell Workflow.

一个选项是将这两行代码包装在 InlineScript 块中。One option is to wrap these two lines of code in an InlineScript block. 在这种情况下,Service 表示块中的服务对象。In this case, Service represents a service object within the block.

Workflow Stop-Service
{
    InlineScript {
        $Service = Get-Service -Name MyService
        $Service.Stop()
    }
}

另一个选项是使用具有相同功能的另一个 cmdlet(如果存在)。Another option is to use another cmdlet that has the same functionality as the method, if one is available. 在我们的示例中,Stop-Service cmdlet 提供了与 Stop 方法相同的功能,可以将以下代码用于工作流。In our example, the Stop-Service cmdlet provides the same functionality as the Stop method, and you might use the following code for a workflow.

Workflow Stop-MyService
{
    $Service = Get-Service -Name MyService
    Stop-Service -Name $Service.Name
}

使用 InlineScriptUse InlineScript

需要将一个或多个命令作为传统 PowerShell 脚本而不是 PowerShell 工作流运行时,InlineScript 活动非常有用。TheInlineScript activity is useful when you need to run one or more commands as traditional PowerShell script instead of PowerShell workflow. 尽管工作流中的命令将发送到 Windows Workflow Foundation 进行处理,但 InlineScript 块中的命令由 Windows PowerShell 处理。While commands in a workflow are sent to Windows Workflow Foundation for processing, commands in an InlineScript block are processed by Windows PowerShell.

InlineScript 使用如下所示的语法。InlineScript uses the following syntax shown below.

InlineScript
{
    <Script Block>
} <Common Parameters>

可以通过将输出分配到一个变量,以返回来自 InlineScript 的输出。You can return output from an InlineScript by assigning the output to a variable. 下面的示例停止一项服务,并输出服务名称。The following example stops a service and then outputs the service name.

Workflow Stop-MyService
{
    $Output = InlineScript {
        $Service = Get-Service -Name MyService
        $Service.Stop()
        $Service
    }

    $Output.Name
}

可将值传递到 InlineScript 块,但必须使用 $Using 作用域修饰符。You can pass values into an InlineScript block, but you must use $Using scope modifier. 下面的示例与前面的示例相同,只是服务名称由变量提供。The following example is identical to the previous example except that the service name is provided by a variable.

Workflow Stop-MyService
{
    $ServiceName = "MyService"

    $Output = InlineScript {
        $Service = Get-Service -Name $Using:ServiceName
        $Service.Stop()
        $Service
    }

    $Output.Name
}

虽然 InlineScript 活动可能在某些工作流中非常关键,但它们不支持工作流构造。While InlineScript activities might be critical in certain workflows, they do not support workflow constructs. 出于以下原因,仅当必要时才应使用它们:You should use them only when necessary for the following reasons:

  • 不能在 InlineScript 块内部使用检查点You can't use checkpoints inside an InlineScript block. 如果块中发生失败,它必须从块的开头恢复。If a failure occurs within the block, it must resume from the beginning of the block.
  • 不能在 InlineScript 块内部使用并行执行You can't use parallel execution inside an InlineScript block.
  • 因为 InlineScript 会在 InlineScript 块的整个长度内占有 Windows PowerShell 会话,因此会影响工作流的可伸缩性。InlineScript affects scalability of the workflow since it holds the Windows PowerShell session for the entire length of the InlineScript block.

有关使用 InlineScript 的详细信息,请参阅在工作流中运行 Windows PowerShell 命令about_InlineScriptFor more information on using InlineScript, see Running Windows PowerShell Commands in a Workflow and about_InlineScript.

使用并行处理Use parallel processing

Windows PowerShell 工作流的一个优点是能够与典型脚本一样并行而不是按顺序执行一组命令。One advantage of Windows PowerShell Workflows is the ability to perform a set of commands in parallel instead of sequentially as with a typical script.

可以使用 Parallel 关键字创建包含将同时运行的多个命令的脚本块。You can use the Parallel keyword to create a script block with multiple commands that run concurrently. 此脚本块使用如下所示的语法。This uses the following syntax shown below. 在此示例中,Activity1 和 Activity2 将同时启动。In this case, Activity1 and Activity2 starts at the same time. 只有在 Activity1 和 Activity2 完成后,Activity3 才会启动。Activity3 starts only after both Activity1 and Activity2 have completed.

Parallel
{
    <Activity1>
    <Activity2>
}
<Activity3>

例如,请注意以下将多个文件复制到网络目标的 PowerShell 命令。For example, consider the following PowerShell commands that copy multiple files to a network destination. 这些命令将依次进行,因此必须完成一个文件的复制,然后才能开始复制下一个文件。These commands are run sequentially so that one file must finish copying before the next is started.

Copy-Item -Path C:\LocalPath\File1.txt -Destination \\NetworkPath\File1.txt
Copy-Item -Path C:\LocalPath\File2.txt -Destination \\NetworkPath\File2.txt
Copy-Item -Path C:\LocalPath\File3.txt -Destination \\NetworkPath\File3.txt

下面的工作流并行运行这些命令,以便它们同时开始复制。The following workflow runs these same commands in parallel so that they all start copying at the same time. 只有在所有复制均已完成之后,才会显示完成消息。Only after they are all copied is the completion message displayed.

Workflow Copy-Files
{
    Parallel
    {
        Copy-Item -Path "C:\LocalPath\File1.txt" -Destination "\\NetworkPath"
        Copy-Item -Path "C:\LocalPath\File2.txt" -Destination "\\NetworkPath"
        Copy-Item -Path "C:\LocalPath\File3.txt" -Destination "\\NetworkPath"
    }

    Write-Output "Files copied."
}

可以使用 ForEach -Parallel 构造同时处理集合中每个项的命令。You can use the ForEach -Parallel construct to process commands for each item in a collection concurrently. 尽管脚本块中的命令按顺序运行,但集合中的项是并行处理的。The items in the collection are processed in parallel while the commands in the script block run sequentially. 此进程使用如下所示的语法。This process uses the following syntax shown below. 在此示例中,将同时对集合中的所有项启动 Activity1。In this case, Activity1 starts at the same time for all items in the collection. 对于每个项,Activity2 会在 Activity1 完成后启动。For each item, Activity2 starts after Activity1 is complete. 只有在对所有项完成 Activity1 和 Activity2 后,Activity3 才会启动。Activity3 starts only after both Activity1 and Activity2 have completed for all items. 我们使用 ThrottleLimit 参数来限制并行度。We use the ThrottleLimit parameter to limit the parallelism. ThrottleLimit 太高会导致问题。Too high of a ThrottleLimit can cause problems. ThrottleLimit 参数的理想值取决于环境中的许多因素。The ideal value for the ThrottleLimit parameter depends on many factors in your environment. 尝试从较低的值开始并尝试不同的增加值,直到找到适合你的特定环境的值。Start with a low value and try different increasing values until you find one that works for your specific circumstance.

ForEach -Parallel -ThrottleLimit 10 ($<item> in $<collection>)
{
    <Activity1>
    <Activity2>
}
<Activity3>

下面的示例是类似于前面的示例,用于并行复制文件。The following example is similar to the previous example copying files in parallel. 在这种情况下,每个文件复制完成之后都会显示一条消息。In this case, a message is displayed for each file after it copies. 只有在所有复制均已完成之后,才会显示最终完成消息。Only after they are all copied is the final completion message displayed.

Workflow Copy-Files
{
    $files = @("C:\LocalPath\File1.txt","C:\LocalPath\File2.txt","C:\LocalPath\File3.txt")

    ForEach -Parallel -ThrottleLimit 10 ($File in $Files)
    {
        Copy-Item -Path $File -Destination \\NetworkPath
        Write-Output "$File copied."
    }

    Write-Output "All files copied."
}

备注

我们不建议并行运行子 Runbook,这是由于这已被证实将导致不可靠的结果。We do not recommend running child runbooks in parallel since this has been shown to give unreliable results. 子 Runbook 的输出有时不显示,一个子 Runbook 中的设置可能会影响其他并行子 Runbook。The output from the child runbook sometimes does not show up, and settings in one child runbook can affect the other parallel child runbooks. VerbosePreferenceWarningPreference 等变量可能不会传播到子 runbook。Variables such as VerbosePreference, WarningPreference, and others might not propagate to the child runbooks. 并且,如果子 runbook 更改这些值,则在调用之后可能无法正确还原这些值。And if the child runbook changes these values, they might not be properly restored after invocation.

在工作流中使用检查点Use checkpoints in a workflow

检查点是工作流当前状态的快照,其中包括变量的当前值以及到该点为止生成的任何输出。A checkpoint is a snapshot of the current state of the workflow that includes the current values for variables and any output generated to that point. 如果工作流以错误或挂起状态结束,则它下次运行时会从其最后一个检查点开始,而不是从开头开始。If a workflow ends in error or is suspended, it starts from its last checkpoint the next time it runs, instead of starting at the beginning.

可以使用 Checkpoint-Workflow 活动在工作流中设置一个检查点。You can set a checkpoint in a workflow with the Checkpoint-Workflow activity. Azure 自动化具有一项名为公平份额的功能,将卸载运行了三小时的任何 runbook,以允许运行其他 runbook。Azure Automation has a feature called fair share, for which any runbook that runs for three hours is unloaded to allow other runbooks to run. 最终,将重新加载已卸载的 runbook。Eventually, the unloaded runbook is reloaded. 重新加载后,将从该 runbook 中已经过的最后一个检查点继续执行。When it is, it resumes execution from the last checkpoint taken in the runbook.

为了保证 runbook 最终完成,必须间隔添加在 3 小时内运行的检查点。To guarantee that the runbook eventually completes, you must add checkpoints at intervals that run for less than three hours. 如果在每次运行期间添加一个新检查点,并在三小时后由于错误而逐出 runbook,则会无限期地恢复该 runbook。If during each run a new checkpoint is added, and if the runbook is evicted after three hours due to an error, the runbook is resumed indefinitely.

在以下示例中,在 Activity2 后发生了异常,导致工作流结束。In the following example, an exception occurs after Activity2, causing the workflow to end. 当工作流再次运行时,它会通过运行 Activity2 来启动,因为此活动刚好在设置的上一个检查点之后。When the workflow is run again, it starts by running Activity2, since this activity was just after the last checkpoint set.

<Activity1>
Checkpoint-Workflow
<Activity2>
<Exception>
<Activity3>

请在可能容易出现异常且在工作流继续时不应重复的活动之后设置检查点。Set checkpoints in a workflow after activities that might be prone to exception and should not be repeated if the workflow is resumed. 例如,工作流可能会创建一个虚拟机。For example, your workflow might create a virtual machine. 可以在命令之前和之后设置一个检查点以创建虚拟机。You can set a checkpoint both before and after the commands to create the virtual machine. 如果创建失败,则当再次启动工作流时会重复命令。If the creation fails, then the commands are repeated if the workflow is started again. 如果创建成功但工作流随后失败,则恢复工作流时不会再次创建虚拟机。If the workflow fails after the creation succeeds, the virtual machine is not created again when the workflow is resumed.

下面的示例将多个文件复制到某个网络位置,并在每个文件复制完成后设置检查点。The following example copies multiple files to a network location and sets a checkpoint after each file. 如果网络位置丢失,则工作流以错误结束。If the network location is lost, then the workflow ends in error. 重新启动时,它将在上一个检查点恢复。When it is started again, it resumes at the last checkpoint. 只会跳过已复制的文件。Only the files that have already been copied are skipped.

Workflow Copy-Files
{
    $files = @("C:\LocalPath\File1.txt","C:\LocalPath\File2.txt","C:\LocalPath\File3.txt")

    ForEach ($File in $Files)
    {
        Copy-Item -Path $File -Destination \\NetworkPath
        Write-Output "$File copied."
        Checkpoint-Workflow
    }

    Write-Output "All files copied."
}

由于调用 Suspend-Workflow 活动后或在最后一个检查点之后,将不保留用户名凭据,所以需要在调用 Suspend-Workflow 或检查点后将凭据设置为 null,然后再从资产存储重新检索凭据。Because user name credentials are not persisted after you call the Suspend-Workflow activity or after the last checkpoint, you need to set the credentials to null and then retrieve them again from the asset store after Suspend-Workflow or checkpoint is called. 否则,可能会收到以下错误消息:The workflow job cannot be resumed, either because persistence data could not be saved completely, or saved persistence data has been corrupted. You must restart the workflow.Otherwise, you might receive the following error message: The workflow job cannot be resumed, either because persistence data could not be saved completely, or saved persistence data has been corrupted. You must restart the workflow.

下面的相同代码演示如何在 PowerShell 工作流 runbook 中处理这种情况。The following same code demonstrates how to handle this situation in your PowerShell Workflow runbooks.

workflow CreateTestVms
{
    $Cred = Get-AzAutomationCredential -Name "MyCredential"
    $null = Connect-AzAccount -Environment AzureChinaCloud -Credential $Cred

    $VmsToCreate = Get-AzAutomationVariable -Name "VmsToCreate"

    foreach ($VmName in $VmsToCreate)
        {
        # Do work first to create the VM (code not shown)

        # Now add the VM
        New-AzVM -VM $Vm -Location "ChinaNorth" -ResourceGroupName "ResourceGroup01"

        # Checkpoint so that VM creation is not repeated if workflow suspends
        $Cred = $null
        Checkpoint-Workflow
        $Cred = Get-AzAutomationCredential -Name "MyCredential"
        $null = Connect-AzAccount -Environment AzureChinaCloud -Credential $Cred
        }
}

备注

对于非图形 PowerShell runbook,Add-AzAccountAdd-AzureRMAccountConnect-AzAccount 的别名。For non-graphical PowerShell runbooks, Add-AzAccount and Add-AzureRMAccount are aliases for Connect-AzAccount. 可以使用这些 cmdlet,也可以在自动化帐户中将模块更新为最新版本。You can use these cmdlets or you can update your modules in your Automation account to the latest versions. 即使刚刚创建了一个新的自动化帐户,也可能需要更新你的模块。You might need to update your modules even if you have just created a new Automation account. 如果使用配置了服务主体的运行方式帐户进行身份验证,则不一定要使用这些 cmdlet。Use of these cmdlets is not required if you are authenticating using a Run As account configured with a service principal.

关于检查点的详细信息,请参阅向脚本工作流添加检查点For more information about checkpoints, see Adding Checkpoints to a Script Workflow.

后续步骤Next steps