在 Azure 自动化中管理 Runbook

可创建新的 Runbook,或从文件或 Runbook 库中导入现有 Runbook,将 Runbook 添加到 Azure 自动化中。 本文提供有关管理 runbook 的信息以及 runbook 设计的建议模式和最佳做法。 可在 Azure 自动化的 Runbook 和模块库中获取有关如何访问社区 Runbook 和模块的全部详细信息。

创建 Runbook

使用 Azure 门户或 PowerShell 在 Azure 自动化中创建新的 Runbook。 Runbook 创建后,就可使用下文中的信息编辑它:

在 Azure 门户中创建 Runbook

  1. 登录 Azure 门户
  2. 搜索并选择“自动化帐户”。
  3. 在“自动化帐户”页上,从列表中选择你的自动化帐户。
  4. 从自动化帐户内,在“流程自动化”下选择“Runbook”,打开 Runbook 的列表 。
  5. 单击“创建 Runbook”。
    1. 命名 runbook。
    2. 在“Runbook 类型”下拉列表中。 选择其类型。 Runbook 名称必须以字母开头,可包含字母、数字、下划线和短划线
    3. 选择“运行时版本”
    4. 输入适用的说明
  6. 单击“创建”以创建 runbook。

通过 PowerShell 创建 Runbook

使用 New-AzAutomationRunbook cmdlet 创建空的 Runbook。 使用 Type 参数指定为 New-AzAutomationRunbook 定义的其中一种 Runbook 类型。

以下示例演示了如何创建新的空 Runbook。

$params = @{
    AutomationAccountName = 'MyAutomationAccount'
    Name                  = 'NewRunbook'
    ResourceGroupName     = 'MyResourceGroup'
    Type                  = 'PowerShell'
}
New-AzAutomationRunbook @params

导入 Runbook

你可以导入 PowerShell 或 PowerShell 工作流 (.ps1) 脚本、图形 Runbook (.graphrunbook) 或者 Python 2 或 Python 3 脚本 (.py) 来创建自己的 Runbook 。 指定在导入期间创建的 Runbook 类型,并考虑以下注意事项。

  • 可将不含工作流的 .ps1 文件导入 PowerShell RunbookPowerShell 工作流 Runbook。 如果将其导入 PowerShell 工作流 Runbook,它将转换为工作流。 这样的话,Runbook 会包含注释来描述所作的更改。

  • 仅可将包含 PowerShell 工作流的 .ps1 文件导入 PowerShell 工作流 Runbook。 如果该文件包含多个 PowerShell 工作流,则导入将失败。 必须将每个工作流保存到各自的文件中,并分别导入每个工作流。

  • 请勿将包含 PowerShell 工作流的 .ps1 文件导入 PowerShell Runbook,因为 PowerShell 脚本引擎无法识别它。

  • 仅可将 .graphrunbook 文件导入新的图形 Runbook

通过 Azure 门户导入 Runbook

可通过以下过程将脚本文件导入 Azure 自动化。

注意

只能通过此门户将 .ps1 文件导入 PowerShell 工作流 Runbook。

  1. 在 Azure 门户中,搜索并选择“自动化帐户”。
  2. 在“自动化帐户”页上,从列表中选择你的自动化帐户。
  3. 从自动化帐户内,在“流程自动化”下选择“Runbook”,打开 Runbook 的列表 。
  4. 单击“导入 Runbook”。 可以选择以下任一选项:
    1. 浏览文件 - 从本地计算机中选择文件。
    2. 从库中浏览 - 可从库中浏览并选择现有的 runbook。
  5. 选择文件。
  6. 如果启用了“名称”字段,则你可更改 Runbook 名称。 该名称必须以字母开头,可包含字母、数字、下划线和短划线。
  7. Runbook 类型”是自动填充的,但可以在考虑适用的限制后更改该类型。
  8. “运行时版本”可以自动填充,也可以从下拉列表中选择版本。
  9. 单击“导入”。 新的 runbook 会出现在自动化帐户的 runbook 列表中。
  10. 必须先发布 Runbook,才能运行它。

注意

导入图形 Runbook 后,可将其转换为其他类型。 但是,无法将图形 Runbook 转换为文本 Runbook。

使用 PowerShell 导入 Runbook

使用 Import-AzAutomationRunbook cmdlet 将脚本文件作为草稿 Runbook 导入。 如果该 Runbook 已存在,则导入将失败,除非你将 Force 参数与 cmdlet 一起使用。

以下示例演示了如何将脚本文件导入到 Runbook 中。

$params = @{
    AutomationAccountName = 'MyAutomationAccount'
    Name                  = 'Sample_TestRunbook'
    ResourceGroupName     = 'MyResourceGroup'
    Type                  = 'PowerShell'
    Path                  = 'C:\Runbooks\Sample_TestRunbook.ps1'
}
Import-AzAutomationRunbook @params

处理资源

如果你的 Runbook 创建了一项资源脚本应检查看看在尝试创建该资源之前它是否已存在。 下面是一个基本示例。

$vmName = 'WindowsVM1'
$rgName = 'MyResourceGroup'
$myCred = Get-AutomationPSCredential 'MyCredential'

$vmExists = Get-AzResource -Name $vmName -ResourceGroupName $rgName
if (-not $vmExists) {
    Write-Output "VM $vmName does not exist, creating"
    New-AzVM -Name $vmName -ResourceGroupName $rgName -Credential $myCred
} else {
    Write-Output "VM $vmName already exists, skipping"
}

从活动日志中检索详细信息

可从自动化帐户的活动日志中检索 Runbook 详细信息,例如启动 Runbook 的人员或帐户。 以下 PowerShell 示例显示了运行指定 Runbook 的最后一名用户。

$rgName = 'MyResourceGroup'
$accountName = 'MyAutomationAccount'
$runbookName = 'MyRunbook'
$startTime = (Get-Date).AddDays(-1)

$params = @{
    ResourceGroupName = $rgName
    StartTime         = $startTime
}
$JobActivityLogs = (Get-AzLog @params).Where( { $_.Authorization.Action -eq 'Microsoft.Automation/automationAccounts/jobs/write' })

$JobInfo = @{}
foreach ($log in $JobActivityLogs) {
    # Get job resource
    $JobResource = Get-AzResource -ResourceId $log.ResourceId

    if ($null -eq $JobInfo[$log.SubmissionTimestamp] -and $JobResource.Properties.Runbook.Name -eq $runbookName) {
        # Get runbook
        $jobParams = @{
            ResourceGroupName     = $rgName
            AutomationAccountName = $accountName
            Id                    = $JobResource.Properties.JobId
        }
        $Runbook = Get-AzAutomationJob @jobParams | Where-Object RunbookName -EQ $runbookName

        # Add job information to hashtable
        $JobInfo.Add($log.SubmissionTimestamp, @($Runbook.RunbookName, $Log.Caller, $JobResource.Properties.jobId))
    }
}
$JobInfo.GetEnumerator() | Sort-Object Key -Descending | Select-Object -First 1

跟踪进度

最佳做法是,使用可轻松重用和重启的逻辑将 Runbook 创作为本质上模块化的内容。 跟踪在 Runbook 中的进度可确保 Runbook 逻辑在出现问题时正确执行。

可使用外部源(例如存储帐户、数据库或共享文件)来跟踪 Runbook 的进度。 在 Runbook 中创建逻辑,从而先检查所执行的最后一个操作的状态。 然后,根据检查结果,可跳过逻辑,或者逻辑在 Runbook 中继续特定任务。

预防并发作业

如果一些 Runbook 同时跨多个作业运行,则它们可能会表现得很奇怪。 在这种情况下,重要的是让 Runbook 实现逻辑来确定是否已有正在运行的作业。 下面是一个基本示例。

# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity 
$AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity).context

# set and store context 
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext

# Check for already running or new runbooks 
$runbookName = "runbookName" 
$resourceGroupName = "resourceGroupName" 
$automationAccountName = "automationAccountName"

$jobs = Get-AzAutomationJob -ResourceGroupName $resourceGroupName -AutomationAccountName $automationAccountName -RunbookName $runbookName -DefaultProfile $AzureContext

# Ranking all the active jobs
$activeJobs = $jobs | where {$_.status -eq 'Running' -or $_.status -eq 'Queued' -or $_.status -eq 'New' -or $_.status -eq 'Activating' -or $_.status -eq 'Resuming'} | Sort-Object -Property CreationTime 
$jobRanking = @() 
$rank = 0 
ForEach($activeJob in $activeJobs) 
{         
    $rank = $rank + 1 
    $activeJob | Add-Member -MemberType NoteProperty -Name jobRanking -Value $rank -Force 
    $jobRanking += $activeJob 
}
    
$AutomationJobId = $PSPrivateMetadata.JobId.Guid 
$currentJob = $activeJobs | where {$_.JobId -eq $AutomationJobId} 
$currentJobRank = $currentJob.jobRanking 

# Only allow the Job with Rank = 1 to start processing. 
If($currentJobRank -ne "1") 
{ 
    Write-Output "$(Get-Date -Format yyyy-MM-dd-hh-mm-ss.ffff) Concurrency check failed as Current Job Ranking is not 1 but $($currentJobRank) therefore exiting..." 
    Exit 
} Else
{
    Write-Output "$(Get-Date -Format yyyy-MM-dd-hh-mm-ss.ffff) Concurrency check passed. Start processing.." 
} 

如果希望 Runbook 使用系统分配的托管标识执行,请按原样保留代码。 如果希望使用用户分配的托管标识,则执行以下操作:

  1. 从第 5 行中删除 $AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity).context
  2. 将其替换为 $AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity -AccountId <ClientId>).context,然后
  3. 输入客户端 ID。

注意

对于 PowerShell 7.2 混合作业,请更改第 28 行。 将 $PSPrivateMetadata.JobId.Guid 替换为 $env:PSPrivateMetaData

处理依赖时间的脚本中的暂时性错误

Runbook 必须可靠且能够处理错误,包括可能导致其重启或失败的暂时性错误。 如果 Runbook 失败,Azure 自动化将重试它。

如果你的 Runbook 通常在一定时间内运行,请让脚本实现逻辑来检查执行时间。 该项检查可确保仅在特定的时间内运行诸如启动、关闭或横向扩展之类的操作。

注意

Azure 沙盒上的本地时间被设置为 UTC。 计算 Runbook 中的日期和时间时,必须考虑到这一事实。

Runbook 中用于避免暂时性故障的重试逻辑

Runbook 通常通过 ARM、Azure Resource Graph、SQL 服务和其他 Web 服务对 Azure 等远程系统发出调用。 当 Runbook 调用的系统繁忙、暂时不可用或在负载下实施限制时,调用很容易出现运行时错误。 若要在 Runbook 中构建复原能力,必须在发出调用时实现重试逻辑,使 Runbook 能够处理暂时性问题而不失败。

有关详细信息,请参阅重试模式以及 REST 和重试一般指导

示例 1:如果 Runbook 只发出一两次调用

$searchServiceURL = "https://$searchServiceName.search.chinacloudapi.cn"
$resource = Get-AzureRmResource -ResourceType "Microsoft.Search/searchServices" -ResourceGroupName $searchResourceGroupName -ResourceName  $searchServiceName -ApiVersion 2015-08-19
$searchAPIKey = (Invoke-AzureRmResourceAction -Action listAdminKeys -ResourceId $resource.ResourceId -ApiVersion 2015-08-19 -Force).PrimaryKey

调用 Invoke-AzureRmResourceAction 时,你可能会遇到暂时性故障。 在这种情况下,建议围绕 cmdlet 调用实现以下基本模式。

$searchServiceURL = "https://$searchServiceName.search.chinacloudapi.cn"
$resource = Get-AzureRmResource -ResourceType "Microsoft.Search/searchServices" -ResourceGroupName $searchResourceGroupName -ResourceName  $searchServiceName -ApiVersion 2015-08-19

    # Adding in a retry
    $Stoploop = $false
    $Retrycount = 0
 
    do {
        try   {
               $searchAPIKey = (Invoke-AzureRmResourceAction -Action listAdminKeys -ResourceId $resource.ResourceId -ApiVersion 2015-08-19 -Force).PrimaryKey
               write-verbose "Invoke-AzureRmResourceAction on $resource.ResourceId completed"
               $Stoploop = $true
              }
        catch {
               if ($Retrycount -gt 3)
                 {
                  Write-verbose "Could not Invoke-AzureRmResourceAction on $resource.ResourceId after 3 retrys."
                  $Stoploop = $true
                 }
               else  
                 {
                  Write-verbose "Could not Invoke-AzureRmResourceAction on $resource.ResourceId retrying in 30 seconds..."
                  Start-Sleep -Seconds 30
                  $Retrycount = $Retrycount + 1
                 }
               }
        }
    While ($Stoploop -eq $false)

注意

最多重试调用三次,每次休眠 30 秒。

示例 2:如果 Runbook 频繁发出远程调用

如果 Runbook 频繁发出远程调用,则它可能会遇到暂时性运行时问题。 创建一个函数用于为发出的每个调用实现重试逻辑,并将要发出的调用作为要执行的脚本块传入。

Function ResilientRemoteCall {

         param(
               $scriptblock
               )
        
         $Stoploop = $false
         $Retrycount = 0
 
         do {
             try   {
                    Invoke-Command -scriptblock $scriptblock 
                    write-verbose "Invoked $scriptblock completed"
                    $Stoploop = $true
                   }
             catch {
                    if ($Retrycount -gt 3)
                      {
                       Write-verbose "Invoked $scriptblock failed 3 times and we will not try again."
                       $Stoploop = $true
                      }
                    else  
                      {
                       Write-verbose "Invoked $scriptblock failed  retrying in 30 seconds..."
                       Start-Sleep -Seconds 30
                       $Retrycount = $Retrycount + 1
                      }
                    }
             }
         While ($Stoploop -eq $false)
}

然后,可将每个远程调用作为
传入该函数

ResilientRemoteCall { Get-AzVm }

ResilientRemoteCall { $searchAPIKey = (Invoke-AzureRmResourceAction -Action listAdminKeys -ResourceId $resource.ResourceId -ApiVersion 2015-08-19 -Force).PrimaryKey}

使用多个订阅

Runbook 必须能够处理订阅。 例如,Runbook 会使用 Disable-AzContextAutosave cmdlet 来处理多个订阅。 该 cmdlet 可确保不从正在同一沙盒中运行的另一 Runbook 中检索身份验证上下文。

# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process

# Connect to Azure with system-assigned managed identity
$AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity).context

# set and store context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription `
    -DefaultProfile $AzureContext

$childRunbookName = 'childRunbookDemo'
$resourceGroupName = "resourceGroupName"
$automationAccountName = "automationAccountName"

$startParams = @{
    ResourceGroupName     = $resourceGroupName
    AutomationAccountName = $automationAccountName
    Name                  = $childRunbookName
    DefaultProfile        = $AzureContext
}
Start-AzAutomationRunbook @startParams

如果希望 Runbook 使用系统分配的托管标识执行,请按原样保留代码。 如果希望使用用户分配的托管标识,则执行以下操作:

  1. 从第 5 行中删除 $AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity).context
  2. 将其替换为 $AzureContext = (Connect-AzAccount -Environment AzureChinaCloud -Identity -AccountId <ClientId>).context,然后
  3. 输入客户端 ID。

使用自定义脚本

注意

通过无法在已安装 Log Analytics 代理的主机上运行自定义脚本和 Runbook。

若要使用自定义脚本:

  1. 创建自动化帐户。
  2. 部署混合 Runbook 辅助角色
  3. 如果是在 Linux 计算机上,则需要提升权限。 登录来关闭签名检查

测试 Runbook

测试 Runbook 时,将执行草稿版,并会完成其所执行的任何操作。 不会创建作业历史记录,但会在“测试输出”窗格中显示输出警告和错误。 仅当 VerbosePreference 变量设置为 Continue 时,“输出”窗格中才会显示发送到详细流的消息。

即使草稿版正在运行,该 Runbook 也仍会正常执行,并针对环境中的资源执行任何操作。 因此,只能在非生产资源中测试 Runbook。

注意

所有 runbook 执行操作都记录在自动化帐户的“活动日志”中,操作名称为“创建Azure 自动化作业”。 但是,在其中执行草稿版本的 runbook 的测试窗格中的 runbook 执行将记录在活动日志中,操作名称为“写入 Azure 自动化 runbook 草稿”。 选择“操作”和“JSON”选项卡可查看以 ../runbooks/(runbook name)/draft/testjob 结尾的范围。

测试各类型的 Runbook 的流程相同。 Azure 门户中文本编辑器测试与图形编辑器测试之间没有区别。

  1. 文本编辑器图形编辑器中打开 Runbook 的草稿版本。
  2. 单击“测试”打开测试页面 。
  3. 如果 Runbook 具有参数,它们会在左窗格中列出,你可在这里提供要用于测试的值。
  4. 若要对混合 Runbook 辅助角色运行测试,请将“运行设置”更改为“混合辅助角色”,并选择目标组的名称 。 否则,保留默认值 Azure,以在云中运行测试。
  5. 单击“启动”,开始测试。
  6. 在测试期间,可使用“输出”窗格下面的按钮来停止或暂停 PowerShell 工作流图形 Runbook。 暂停 Runbook 时,该 Runbook 会完成它在被暂停之前正在进行的活动。 暂停 Runbook 后,可以将它停止或重启。
  7. 在“输出”窗格中检查来自 Runbook 的输出。

发布 Runbook

创建或导入新的 Runbook 时,必须先将其发布,然后才能导入。 Azure 自动化中的每个 Runbook 都有一个草稿版本和一个已发布版本。 只有已发布版才能用来运行,只有草稿版才能用来编辑。 已发布版不受对草稿版所做的任何更改的影响。 当应该提供草稿版本时,你要发布它,使用草稿版本覆盖当前的已发布版本。

在 Azure 门户中发布 Runbook

  1. 在 Azure 门户中,搜索并选择“自动化帐户”。
  2. 在“自动化帐户”页上,从列表中选择你的自动化帐户。
  3. 用你自己的自动化帐户打开 runbook。
  4. 单击 “编辑”
  5. 单击“发布”,然后在对验证消息的响应中选择“是” 。

使用 PowerShell 运行 Runbook

使用 Publish-AzAutomationRunbook cmdlet 发布 Runbook。

$accountName = "MyAutomationAccount"
$runbookName = "Sample_TestRunbook"
$rgName = "MyResourceGroup"

$publishParams = @{
    AutomationAccountName = $accountName
    ResourceGroupName     = $rgName
    Name                  = $runbookName
}
Publish-AzAutomationRunbook @publishParams

在 Azure 门户中计划 Runbook

当你的 Runbook 已发布后,可计划它进行操作:

  1. 在 Azure 门户中,搜索并选择“自动化帐户”。
  2. 在“自动化帐户”页上,从列表中选择你的自动化帐户。
  3. 从 runbook 列表中选择该 runbook。
  4. 在“资源”下选择“计划” 。
  5. 选择“添加计划”。
  6. 在“计划 Runbook”窗格中,选择“将计划关联到 Runbook” 。
  7. 在“计划”窗格中选择“创建新计划” 。
  8. 在“新建计划”窗格中输入名称、说明和其他参数。
  9. 创建计划后,将其突出显示并单击“确定”。 它现应与你的 Runbook 关联。
  10. 查看邮箱中的电子邮件,里面有 Runbook 的状态。

还原删除的 Runbook

可以通过 PowerShell 脚本恢复删除的 Runbook。 要恢复 Runbook,请确保满足以下条件:

  • 过去 29 天内删除了要还原的 Runbook。
  • 该 Runbook 的自动化帐户存在。
  • 自动化参与者角色权限授予自动化帐户的系统分配托管标识。

PowerShell 脚本

  • 在自动化帐户中将 PowerShell 脚本作为作业执行,以还原删除的 Runbook。
  • 从 GitHub 下载 PowerShell 脚本。 或者,可以从 Runbook 库中导入名为还原自动化 Runbook的 PowerShell 脚本。 提供要还原的 Runbook 的名称,并将其作为作业在 Azure 自动化中运行,以还原删除的 Runbook。
  • 从 GitHub 下载脚本,或从 Runbook 库中导入名为列出删除的自动化 Runbook的 PowerShell 脚本,以确定在过去 29 天内删除的 Runbook 的名称。

获取作业状态

在 Azure 门户中查看状态

可通过作业查看在 Azure 自动化中处理的作业的详细信息。 准备好查看 Runbook 作业后,使用 Azure 门户并访问你的自动化帐户。 你可在右侧的“作业统计信息”中看到所有 Runbook 作业的摘要。

Job Statistics tile

该摘要显示了所执行的每项作业的状态的计数和图形表示形式。

单击磁贴可显示“作业”页面,其中有所执行的全部作业的汇总列表。 该页面会显示每项作业的状态、Runbook 名称、开始时间和完成时间。

Screenshot of the Jobs page.

可选择“筛选作业”来筛选作业的列表。 根据特定 Runbook、作业状态或从下拉列表中选择的内容进行筛选,并提供搜索的时间范围。

Filter job status

或者,可从自动化帐户中的 Runbook 页面上选择特定的 Runbook,然后选择“作业”来查看该 Runbook 的作业摘要详情。 该操作会显示“作业”页面。 你可在这里单击作业记录,查看它的详细信息和输出内容。

Screenshot of the Jobs page with the Errors button highlighted.

使用 PowerShell 检索作业状态

使用 Get-AzAutomationJob cmdlet 检索为 Runbook 创建的作业和特定作业的详细信息。 如果使用 Start-AzAutomationRunbook 启动 Runbook,它会返回生成的作业。 使用 Get-AzAutomationJobOutput 检索作业输出。

以下示例会获取示例 Runbook 的最后一项作业,并显示它的状态、为 Runbook 参数提供的值以及作业的输出内容。

$getJobParams = @{
    AutomationAccountName = 'MyAutomationAccount'
    ResourceGroupName     = 'MyResourceGroup'
    Runbookname           = 'Test-Runbook'
}
$job = (Get-AzAutomationJob @getJobParams | Sort-Object LastModifiedDate -Desc)[0]
$job | Select-Object JobId, Status, JobParameters

$getOutputParams = @{
    AutomationAccountName = 'MyAutomationAccount'
    ResourceGroupName     = 'MyResourceGroup'
    Id                    = $job.JobId
    Stream                = 'Output'
}
Get-AzAutomationJobOutput @getOutputParams

以下示例会检索特定作业的输出,并返回每条记录。 如果其中一个记录出现异常,脚本将写出异常而不是值。 此行为非常有用,因为异常可提供在输出过程中可能无法正常记录的其他信息。

$params = @{
    AutomationAccountName = 'MyAutomationAccount'
    ResourceGroupName     = 'MyResourceGroup'
    Stream                = 'Any'
}
$output = Get-AzAutomationJobOutput @params

foreach ($item in $output) {
    $jobOutParams = @{
        AutomationAccountName = 'MyAutomationAccount'
        ResourceGroupName     = 'MyResourceGroup'
        Id                    = $item.StreamRecordId
    }
    $fullRecord = Get-AzAutomationJobOutputRecord @jobOutParams

    if ($fullRecord.Type -eq 'Error') {
        $fullRecord.Value.Exception
    } else {
        $fullRecord.Value
    }
}

后续步骤