57、PowerShell 工作流:暂停、恢复、嵌入脚本与并行执行

PowerShell 工作流:暂停、恢复、嵌入脚本与并行执行

1. 工作流的暂停与恢复

在编写 PowerShell 工作流时,考虑 PowerShell 可以安全暂停工作流的点非常重要。任何仅依赖工作流变量或重启后仍存在的系统状态的点,都是安全的暂停点。在这些点上,可以添加对 Checkpoint-Workflow 命令的调用。

以下是一个示例工作流:

workflow Invoke-MyFirstWorkflow
{
    ## Run step 1
    InlineScript
    {
        "Starting step 1"
        Start-Sleep -Seconds 5
        "Ending step 1"
    }
    Checkpoint-Workflow
    ## Run step 2
    InlineScript
    {
        "Starting step 2"
        Start-Sleep -Seconds 5
        "Ending step 2"
    }
    Checkpoint-Workflow
    ## Run step 3
    \\workflowserver\scripts\step3.ps1
}

定义了检查点后,就可以暂停和恢复工作流:

PS > $j = Invoke-MyFirstWorkflow -AsJob
PS > Suspend-Job $j
PS > $j
Id     Name            PSJobTypeName   State         HasMoreData
--     ----            -------------   -----         -----------
14     Job14           PSWorkflowJob   Suspended     True       
PS > Receive-Job $j
Starting step 1
Ending step 1
PS > Resume-Job $j
PS > $j
Id     Name            PSJobTypeName   State         HasMoreData
--     ----            -------------   -----         -----------
14     Job14           PSWorkflowJob   Running       True       
PS > Receive-Job $j
Starting step 2
Ending step 2
PS > Receive-Job $j
<Output from step3.ps1>

若要让 PowerShell 在继续执行之前等待任何 *-Job cmdlet 进入预期状态,可以使用 -Wait 参数。

调用 Suspend-Job cmdlet 时,PowerShell 会继续运行代表该作业的工作流,直到到达下一个定义的持久化点。如果情况紧急,可以使用 Suspend-Job -Force 参数,但应尽量避免,因为后果可能很严重。使用 -Force 参数时,PowerShell 会强制终止工作流,并在恢复时从最后保存的检查点恢复。

如果工作流的每个步骤都仅依赖工作流变量或重启后仍存在的系统状态,可以使用 $PSPersistPreference 变量让 PowerShell 在每个命令后检查点工作流。但要谨慎使用此设置,因为它告诉 PowerShell 用户可以在任何时候暂停工作流并重启机器。

workflow Invoke-MyFirstWorkflow
{
    $PSPersistPreference = $true
    ## Run step 1
    InlineScript
    {
        "Starting step 1"
        Start-Sleep -Seconds 5;
        "Ending step 1"
    }
    ## Run step 2
    InlineScript
    {
        "Starting step 2"
        Start-Sleep -Seconds 5;
        "Ending step 2"
    }
    ## Run step 3
    \\workflowserver\scripts\step3.ps1
}
2. 嵌入传统 PowerShell 脚本

在编写工作流时,可能希望包含传统 PowerShell 脚本的部分。可以使用 InlineScript 关键字来定义传统 PowerShell 脚本的区域。如果该脚本需要工作流中的变量,可以使用 $USING 前缀引用它们。

以下是一个示例工作流:

workflow Invoke-Backup
{
    param([PSCredential] $FtpCredential)
    ## Each step is safe to persist after
    $PSPersistPreference = $true
    ## Create a backup
    Get-ChildItem -Path c:\ImportantDocuments |
        New-ZipFile -Path c:\temp\backup.zip
    ## And upload it to the server
    InlineScript
    {
        $credential = $USING:FtpCredential
        $wc = New-Object System.Net.WebClient
        $wc.Credentials = $credential.GetNetworkCredential()
        $wc.UploadFile("ftp://server.com/backups/backup.zip",
            "c:\temp\backup.zip")
    }
}
$cred = Get-Credential
Invoke-Backup -FtpCredential $cred

InlineScript 关键字自动支持远程连接、多机器目标、自动持久化点等。例如,要让 InlineScript 在调用时针对特定计算机(而不是工作流目标),可以使用 -PSComputerName 参数。

workflow Invoke-InlineScriptTargeting
{
    ## Run on whatever computer is being targeted
    InlineScript
    {
        "Running on $USING:PSComputername"
    }

    ## Run on the workflow server
    InlineScript
    {
        "Running on $USING:PSComputername"
    } -PSComputerName localhost
}
PS > Invoke-InlineScriptTargeting -PSComputerName Computer1
Running on Computer1
Running on localhost
3. 并行执行工作流操作

当编写工作流时,有些任务可以同时运行以加快速度。可以使用 parallel foreach -parallel 语句并行调用操作。在 parallel 语句中,使用 sequence 语句将应作为一个单元处理的语句分组。

以下是一个示例工作流:

workflow Invoke-Parallel
{
    parallel
    {
        ## Segment 1: Sleep for 5 seconds
        sequence
        {
            "Starting 5 second sleep"
            Start-Sleep -Seconds 5
            "Ending 5 second sleep"
        }
        ## Segment 2: Sleep for 4 seconds
        sequence
        {
            "Starting 4 second sleep"
            Start-Sleep -Seconds 4
            "Ending 4 second sleep"
        }
        ## Segment 3: Process 3 items in
        ## parallel, each of them sleeping for
        ## 2, 4, or 6 seconds
        foreach -parallel ($item in 1..3)
        {
            "Starting sleep for $item"
            Start-Sleep -Seconds (2 * $item)
            "Ending sleep for $item"
        }
    }
}

parallel 语句中,PowerShell 大致同时调用花括号内的每个命令。如果 parallel 块中有两个或更多语句应作为一个单元调用(顺序执行而不是并行执行),则将它们放在 sequence 块中。

如果要在 parallel 语句中更改或修改在其外部定义的变量,必须使用 $WORKFLOW 变量前缀。

需要注意的是,在 parallel 语句中更改共享工作流级变量时要小心,因为块是并行运行的,变量赋值的顺序没有保证,这就是所谓的竞争条件。以下是一个有竞争条件的工作流示例:

workflow Invoke-WorkflowWithRaceCondition
{
    $counter = 0
    parallel
    {
        ## Segment 1 - retrieve the value of counter,
        ## wait for a while, add one to that value,
        ## and store the result
        sequence
        {
            $myValue = $counter
            Start-Sleep -Seconds 2
            $WORKFLOW:counter = $myValue + 1
        }
        ## Segment 2 - retrieve the value of counter,
        ## wait for a while, add one to that value,
        ## and store the result
        sequence
        {
            $myValue = $counter
            Start-Sleep -Seconds 2
            $WORKFLOW:counter = $myValue + 1
        }
    }
    ## You might expect "2" here. However, since both
    ## segments read the value of $counter while it
    ## was "0", they both end up setting the result to "1".
    "After 2 updates, counter is: $counter"
}
PS > Invoke-WorkflowWithRaceCondition
After 2 updates, counter is: 1

当涉及并行调用时,最常见的机会之一是处理列表中的项目。如果处理集合中的一个项目不需要处理其他项目的结果,可以使用 foreach -parallel 语句同时处理这些项目。

workflow Invoke-ParallelDataProcessing
{
    $items = "Item1","Item2","Item3"
    ## Go through each item in the collection
    ## and process it.
    foreach -parallel ($item in $items)
    {
        "Processing item $item"
        Start-Sleep -Seconds 2
        "Done processing item $item"
    }
}
PS > Invoke-ParallelDataProcessing
Processing item Item3
Processing item Item2
Processing item Item1
Done processing item Item3
Done processing item Item2
Done processing item Item1
4. 自定义活动的连接参数

在编写工作流时,可能希望自定义特定命令或活动的连接行为。可以为任何常见活动参数提供值,以自定义其连接或工作流行为。

以下是一个示例工作流:

workflow Invoke-InlineScriptTargeting
{
    ## Run on whatever computer is being targeted
    InlineScript
    {
        "Running on $USING:PSComputername"
    }

    ## Run on the workflow server
    InlineScript
    {
        "Running on $USING:PSComputername"
    } -PSComputerName localhost
}
PS > Invoke-InlineScriptTargeting -PSComputerName Computer1
Running on Computer1
Running on localhost

工作流中的每个命令都支持大量常见参数,这些是参数级工作流常见参数。工作流本身也会自动获得许多工作流常见参数,这些是工作流级常见参数,使用户可以轻松将工作流目标设定为多台机器。

以下是工作流常见参数的表格:
| Parameter | Meaning |
| — | — |
| AppendOutput | Parameter-level only
指定 PowerShell 应将命令的结果添加到用于保存结果的变量中,而不是重置它(变量赋值通常会重置)。在工作流中使用 += 运算符时,PowerShell 会自动执行此操作,因此很少直接指定。 |
| AsJob | Workflow-level only
确定 PowerShell 是否应返回创建的作业并将控制权返回给 shell。默认是模拟交互式命令,等待作业完成。 |
| Debug | Workflow-level and parameter-level
与传统 PowerShell 命令一样,指定 PowerShell 应为指定命令启用调试输出流。 |
| DisplayName | Parameter-level only
定义在编写进度消息时应使用的当前活动的显示名称。 |
| ErrorAction | Workflow-level and parameter-level
与传统 PowerShell 命令一样,定义工作流应如何处理错误条件。 |
| Input | Parameter-level only
定义应使用的集合来表示传统 PowerShell 管道输入的概念。很少直接指定,因为通过管道为活动提供输入更有效。 |
| JobName | Workflow-level only
PowerShell 创建的作业使用的作业名称。默认是自动生成的作业名称。 |
| MergeErrorToOutput | Parameter-level only
指定 PowerShell 应将命令的错误视为输出。在工作流中使用流重定向运算符时,PowerShell 会自动执行此操作,因此很少直接指定。 |
| PSActionRetryCount | Parameter-level only
如果初始调用尝试导致错误,PowerShell 应尝试调用指定命令的次数。此参数的默认值为 0。除非超过此限制,否则 PowerShell 不会报告失败的重试尝试的错误。 |
| PSActionRetryIntervalSec | Parameter-level only
PowerShell 在命令重试尝试之间应等待的时间(以秒为单位)。此参数的默认值为 1 秒。 |
| PSActionRunningTimeoutSec | Parameter-level only
此命令应允许运行的最长时间(以秒为单位)。此参数的默认值为无限制。 |
| PSAllowRedirection | Workflow-level and parameter-level
确定 PowerShell 是否应允许将远程连接重定向到另一个 URI。默认值为 $false 。 |
| PSApplicationName | Workflow-level and parameter-level
用于远程连接的应用程序名称。默认是 WSMan。 |
| PSAuthentication | Workflow-level and parameter-level
用于远程连接的身份验证机制。在域环境中默认使用 Kerberos,在工作组中使用 Negotiate。 |
| PSAuthenticationLevel | Workflow-level and parameter-level
用于远程 WMI 连接的身份验证级别。默认是 Packet 身份验证。 |
| PSCertificateThumbprint | Workflow-level and parameter-level
用于远程连接标识用户的证书指纹。默认是不使用证书指纹。 |
| PSComputerName | Workflow-level and parameter-level
用于远程连接的计算机名称。默认情况下,PowerShell 目标是当前机器。 |
| PSConfigurationName | Workflow-level and parameter-level
用于远程连接的应用程序名称。默认是 Microsoft.PowerShell。 |
| PSConnectionRetryCount | Workflow-level and parameter-level
如果初始连接尝试返回错误,PowerShell 应尝试连接到计算机的次数。此参数的默认值为 0。除非超过此限制,否则 PowerShell 不会报告失败的连接尝试的错误。 |
| PSConnectionRetryIntervalSec | Workflow-level and parameter-level
PowerShell 在重新连接尝试之间应等待的时间(以秒为单位)。此参数的默认值为 1 秒。 |
| PSConnectionUri | Workflow-level and parameter-level
用于远程连接的连接 URI。默认是 http://localhost:5985/WSMan。 |
| PSCredential | Workflow-level and parameter-level
PowerShell 用于远程连接的凭据。默认情况下,PowerShell 使用运行工作流的用户的凭据。 |
| PSDebug | Parameter-level only
指定保存命令生成的任何调试输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存调试输出。 |
| PSDisableSerialization | Parameter-level only
指定活动默认不应序列化其输出。使用此参数时要小心,因为禁用序列化时,大多数命令输出无法正确持久化。如果工作流需要处理实时对象,则需要此参数。 |
| PSElapsedTimeoutSec | Workflow-level and parameter-level
此工作流应允许运行的最长时间(以秒为单位)。此参数的默认值为无限制。工作流中暂停的时间计入其经过时间。 |
| PSError | Parameter-level only
指定保存命令生成的任何错误输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存错误输出。 |
| PSParameterCollection | Workflow-level only
一个哈希表列表,定义 PowerShell 为批量调用工作流提供的参数。 |
| PSPersist | Workflow-level, preference, and parameter
在工作流或首选项级别指定时,强制 PowerShell 在每个命令后检查点运行的工作流,除非该工作流(或其命令)提供了显式的 PSPersist 值。使用此设置时要小心,因为它告诉 PowerShell 用户可以在任何时候暂停工作流并重启机器,即使这不是工作流作者的意图。在参数级别指定时,强制 PowerShell 在命令完成后检查点运行的工作流。此参数很少在参数级别直接指定,因为 Checkpoint-Workflow 命令是表达此意图更清晰的方式。 |
| PSPort | Workflow-level and parameter-level
用于远程连接的端口。默认是 5985 和 5986(对于基于 SSL 的连接)。 |
| PSProgress | Parameter-level only
指定保存命令生成的任何进度输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存进度输出。 |
| PSProgressMessage | Parameter-level only
定义执行此命令时要显示的进度消息。 |
| PSPrivateMetadata | Workflow-level and parameter-level
与工作流关联的附加数据,用于以后的过滤。 |
| PSRemotingBehavior | Parameter-level only
定义此命令应如何处理远程连接。值为 None 表示应忽略 PSComputerName 参数(或工作流级首选项)。值为 Custom 表示如果命令定义了 -ComputerName 参数,则应将 PSComputerName 参数的值提供给该命令的实际 -ComputerName 参数。值为 PowerShell 表示应使用常规 PowerShell 远程连接处理远程连接。大多数命令的默认值为 PowerShell 。 |
| PSRequiredModules | Parameter-level only
定义 PowerShell 在调用命令之前应加载到目标会话中的模块。仅当 PowerShell 的自动加载不足时才需要此参数,例如模块不在标准 PSModulePath 目录中,或者模块定义了命令所需的 PowerShell 提供程序。 |
| PSRunningTimeoutSec | Workflow-level only
此工作流应允许主动运行的最长时间(以秒为单位)。此参数的默认值为无限制。工作流中暂停的时间不计入其运行时间。 |
| PSSessionOption | Workflow-level and parameter-level
用于远程连接的任何附加连接选项,由 New-PSSessionOption cmdlet 定义。默认是无附加选项。 |
| PSUseSsl | Workflow-level and parameter-level
确定 PowerShell 在进行远程连接时是否应连接到 SSL 端点。 |
| PSVerbose | Parameter-level only
指定保存命令生成的任何详细输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存详细输出。 |
| PSWarning | Parameter-level only
指定保存命令生成的任何警告输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存警告输出。 |
| Result | Parameter-level only
指定保存命令生成的任何常规输出的集合。很少直接指定,因为 PowerShell 会自动使用默认集合填充此参数以保存常规输出。 |
| UseDefaultInput | Parameter-level only
指定命令应从 PowerShell 工作流引擎维护的输入集合中检索其输入。很少直接指定,因为 PowerShell 在需要时会填充此参数。 |
| Verbose | Workflow-level and parameter-level
与传统 PowerShell 命令一样,指定 PowerShell 应为指定命令启用详细输出流。 |
| WarningAction | Workflow-level and parameter-level
与传统 PowerShell 命令一样,定义工作流应如何处理警告条件。 |

对于任何受支持的常见参数,PowerShell 通过只读自动变量提供这些参数的值。例如,工作流可以访问 $PSComputerName 变量(以及许多其他变量),以便在处理时可能对其值做出反应(或记录)。

如果要在 InlineScript 中使用这些变量,请务必使用 $USING 变量前缀。要一次性查看所有值,可以使用 Get-PSWorkflowData 命令作为替代变量引用特定设置的方法。由于很容易因意外为常规脚本选择相同的变量名而覆盖这些变量之一,PowerShell 会阻止更改这些值。

以下是一个简单的 mermaid 流程图,展示工作流的基本执行流程:

graph LR
    A[开始工作流] --> B[执行步骤1]
    B --> C{是否有检查点}
    C -- 是 --> D[保存检查点]
    C -- 否 --> E[继续执行步骤2]
    D --> E
    E --> F{是否有并行任务}
    F -- 是 --> G[并行执行任务]
    F -- 否 --> H[顺序执行任务]
    G --> I[合并结果]
    H --> I
    I --> J[执行步骤3]
    J --> K[结束工作流]

通过以上内容,我们可以看到 PowerShell 工作流提供了强大的功能,包括暂停和恢复、嵌入传统脚本、并行执行和自定义连接参数等。合理使用这些功能可以提高工作流的效率和可维护性。

PowerShell 工作流:暂停、恢复、嵌入脚本与并行执行

5. 工作流操作的实际应用场景分析

工作流的各种操作在实际应用中有不同的价值,以下是一些具体场景分析:
- 暂停与恢复工作流 :在进行大规模数据处理时,若遇到系统资源紧张的情况,可暂停工作流,待资源充足时再恢复,避免因资源不足导致任务失败。例如,在备份大量文件时,若服务器磁盘 I/O 过高,可暂停备份工作流,等磁盘 I/O 降低后再恢复。
- 嵌入传统 PowerShell 脚本 :当工作流中需要使用一些现有的传统 PowerShell 脚本时,使用 InlineScript 关键字可以方便地将其集成到工作流中。比如,在自动化部署应用程序的工作流中,嵌入传统的脚本进行环境配置检查。
- 并行执行工作流操作 :在处理多个独立的任务时,并行执行可以显著提高效率。例如,同时对多个服务器进行性能数据采集,每个服务器的采集任务相互独立,使用 parallel foreach -parallel 语句可以同时进行采集。

6. 工作流常见参数的使用技巧

在实际使用工作流常见参数时,有一些技巧可以帮助我们更好地控制工作流:
- 参数的优先级 :工作流级别的参数会作为活动级参数的默认值,但如果在活动中显式指定了参数值,则以活动中的值为准。例如,在工作流中设置了全局的 PSComputerName ,但在某个 InlineScript 中又指定了不同的 PSComputerName ,则该 InlineScript 会使用自己指定的值。
- 批量操作参数 PSParameterCollection 参数可以用于批量调用工作流。例如:

$j = Invoke-WorkflowMath -AsJob -PSParameterCollection @{
    Number1 = 10; Number2 = 20}, @{ Number1 = 20; Number2 = 30 }
Receive-Job $j.ChildJobs[0]
Receive-Job $j.ChildJobs[1]

这样可以一次性为工作流提供多组参数,实现批量处理。

7. 避免工作流中的竞争条件

如前文所述,在并行执行工作流时,竞争条件是一个需要注意的问题。为了避免竞争条件,可以采取以下措施:
- 使用锁机制 :虽然 PowerShell 本身没有内置的锁机制,但可以通过一些外部手段来模拟。例如,使用文件锁,在访问共享资源前检查文件是否存在,若存在则等待,若不存在则创建文件并访问资源,访问完成后删除文件。
- 设计无共享状态的并行任务 :尽量让并行任务之间不共享变量,每个任务独立完成自己的工作,避免因变量赋值顺序不确定导致的问题。

8. 工作流的错误处理与调试

在工作流中,错误处理和调试是非常重要的环节。以下是一些建议:
- 错误处理 :使用 ErrorAction 参数可以定义工作流如何处理错误条件。例如,设置 ErrorAction Stop ,当遇到错误时工作流会立即停止,便于及时发现问题。
- 调试 :使用 Debug 参数可以启用调试输出流,帮助我们查看工作流的执行过程。同时,在 InlineScript 中使用 $USING 前缀引用工作流变量进行调试。

9. 工作流的性能优化

为了提高工作流的性能,可以从以下几个方面进行优化:
- 合理使用检查点 :检查点的保存和恢复会带来一定的性能开销,因此应合理设置检查点的位置,避免不必要的检查点。
- 优化并行任务 :在并行执行任务时,要确保任务之间的独立性,避免因任务之间的依赖关系导致并行效率降低。同时,合理分配系统资源,避免资源竞争。

10. 总结与展望

PowerShell 工作流提供了丰富的功能,包括暂停和恢复、嵌入传统脚本、并行执行和自定义连接参数等。通过合理使用这些功能,可以提高工作流的效率、可维护性和可靠性。

在未来,随着 PowerShell 的不断发展,工作流可能会支持更多的高级功能,如更复杂的并行调度算法、更强大的错误处理机制等。同时,与其他自动化工具的集成也可能会更加紧密,为用户提供更全面的自动化解决方案。

以下是一个 mermaid 流程图,展示工作流性能优化的步骤:

graph LR
    A[开始工作流] --> B[分析工作流]
    B --> C{是否有性能瓶颈}
    C -- 是 --> D[确定瓶颈位置]
    C -- 否 --> E[继续执行工作流]
    D --> F{瓶颈类型}
    F -- 检查点开销 --> G[调整检查点位置]
    F -- 并行效率低 --> H[优化并行任务]
    G --> I[重新测试性能]
    H --> I
    I --> J{性能是否提升}
    J -- 是 --> E
    J -- 否 --> K[进一步分析优化]
    K --> D

通过以上对 PowerShell 工作流的深入探讨,我们可以更好地利用其功能,为自动化任务提供更高效的解决方案。在实际应用中,要根据具体需求合理选择和使用工作流的各种特性,不断优化工作流以提高性能和可靠性。

以下是一个总结性的表格,展示工作流不同操作的关键要点:
| 操作类型 | 关键要点 |
| — | — |
| 暂停与恢复工作流 | 确定安全的暂停点,使用 Checkpoint-Workflow 命令,谨慎使用 -Force 参数,合理设置 $PSPersistPreference 变量。 |
| 嵌入传统 PowerShell 脚本 | 使用 InlineScript 关键字,使用 $USING 前缀引用工作流变量,可使用 -PSComputerName 参数指定目标计算机。 |
| 并行执行工作流操作 | 使用 parallel foreach -parallel 语句,使用 sequence 语句分组顺序执行的任务,使用 $WORKFLOW 前缀修改外部变量,避免竞争条件。 |
| 自定义活动的连接参数 | 了解各种常见参数的含义和作用,注意参数的优先级和批量操作参数的使用。 |

希望以上内容能帮助你更好地掌握 PowerShell 工作流的相关知识和技能,在实际工作中发挥更大的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值