关于作业

简短说明

提供有关 PowerShell 后台作业如何在不与当前会话交互的情况下在后台运行命令或表达式的信息。

长说明

PowerShell 通过作业并发运行命令和脚本。 PowerShell 提供三种作业类型来支持并发。

  • RemoteJob - 命令和脚本在远程会话上运行。 有关信息,请参阅 about_Remote_Jobs
  • BackgroundJob - 命令和脚本在本地计算机上的单独进程中运行。
  • PSTaskJobThreadJob - 命令和脚本在本地计算机上的同一进程中的单独线程中运行。 有关详细信息,请参阅 about_Thread_Jobs

在单独的计算机上或在单独的进程中远程运行脚本可提供很好的隔离。 远程作业中发生的任何错误不会影响其他正在运行的作业或启动该作业的父会话。 但是,远程处理层会增加开销,包括对象序列化。 在父会话与远程 (作业) 会话之间传递时,所有对象都会进行序列化和反序列化。 序列化大型复杂数据对象可能会消耗大量的计算和内存资源,并跨网络传输大量数据。

基于线程的作业不像远程和后台作业那样可靠,因为它们在不同的线程上的同一进程中运行。 如果一个作业出现导致进程崩溃的严重错误,则进程中的所有其他作业都会终止。

但是,基于线程的作业需要的开销更少。 它们不使用远程处理层或序列化。 结果对象作为对当前会话中的活动对象的引用返回。 如果没有这种开销,基于线程的作业的运行速度更快,使用的资源比其他作业类型少。

重要

创建作业的父会话还会监视作业状态并收集管道数据。 作业达到完成状态后,父进程将终止作业子进程。 如果终止父会话,则所有正在运行的子作业将连同其子进程一起终止。

可通过两种方法绕过此限制:

  1. 使用 Invoke-Command 创建在断开连接的会话中运行的作业。 有关详细信息,请参阅 about_Remote_Jobs
  2. 使用 Start-Process 创建新进程,而不是作业。 有关详细信息,请参阅 Start-Process

作业 cmdlet

Cmdlet 说明
Start-Job 在本地计算机上启动后台作业。
Get-Job 获取在 中启动的后台作业
当前会话。
Receive-Job 获取后台作业的结果。
Stop-Job 停止后台作业。
Wait-Job 禁止显示命令提示符,直到有一个或所有作业
完成。
Remove-Job 删除后台作业。
Invoke-Command AsJob 参数在 上创建后台作业
远程计算机。 可以使用 Invoke-Command 来运行
远程任何作业命令,包括 Start-Job

如何在本地计算机上启动作业

若要在本地计算机上启动后台作业,请使用 Start-Job cmdlet。

若要编写 Start-Job 命令,请将作业运行的命令括在大括号 ({}) 。 使用 ScriptBlock 参数指定命令。

以下命令启动一个在本地计算机上运行 Get-Process 命令的后台作业。

Start-Job -ScriptBlock {Get-Process}

启动后台作业时,即使作业需要较长时间才能完成,命令提示符也会立即返回。 当该作业运行时,你可以继续在此会话中工作而不会发生中断。

命令 Start-Job 返回一个表示作业的 对象。 作业对象包含有关该作业的有用信息,但是不包含作业结果。

可以将作业对象保存在变量中,然后将其与其他 作业 cmdlet 一起使用来管理后台作业。 以下命令启动一个作业对象,并将生成的作业对象保存在 变量中 $job

$job = Start-Job -ScriptBlock {Get-Process}

从 PowerShell 6.0 开始,可以使用管道末尾的后台运算符 (&) 来启动后台作业。 有关详细信息,请参阅 后台运算符

使用后台运算符在功能上等同于在上一示例中使用 Start-Job cmdlet。

$job = Get-Process &

获取作业对象

cmdlet Get-Job 返回表示在当前会话中启动的后台作业的对象。 如果没有参数, Get-Job 则返回在当前会话中启动的所有作业。

Get-Job

作业对象包含作业的状态,该状态指示作业是否已完成。 已完成作业的状态为 “完成”“失败”。 作业也可能为 “已阻止 ”或 “正在运行”。

Id  Name  PSJobTypeName State      HasMoreData  Location   Command
--  ----  ------------- -----      -----------  --------   -------
1   Job1  BackgroundJob Complete   True         localhost  Get-Process

可以将作业对象保存在变量中,并在后面的命令中使用它来表示作业。 以下命令获取 ID 为 1 的作业,并将其保存在 变量中 $job

$job = Get-Job -Id 1

获取作业结果

运行后台作业时,结果不会立即显示。 若要获取后台作业的结果,请使用 Receive-Job cmdlet。

以下示例中 Receive-Job ,cmdlet 使用 变量中的 $job 作业对象获取作业的结果。

Receive-Job -Job $job
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)    Id ProcessName
-------  ------    -----      ----- -----   ------    -- -----------
    103       4    11328       9692    56           1176 audiodg
    804      14    12228      14108   100   101.74  1740 CcmExec
    668       7     2672       6168   104    32.26   488 csrss
...

可以将作业的结果保存在变量中。 以下命令将 变量中 $job 作业的结果保存到 $results 变量。

$results = Receive-Job -Job $job

获取和保留部分作业结果

cmdlet Receive-Job 获取后台作业的结果。 如果作业已完成, Receive-Job 则获取所有作业结果。 如果作业仍在运行, Receive-Job 则获取到目前为止已生成的结果。 可以再次运行 Receive-Job 命令来获取剩余结果。

默认情况下, Receive-Job 从存储作业结果的缓存中删除结果。 再次运行时 Receive-Job ,只会获得第一次运行后到达的新结果。

以下命令显示作业完成前运行的命令的结果 Receive-Job

C:\PS> Receive-Job -Job $job

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    103       4    11328       9692    56            1176 audiodg
    804      14    12228      14108   100   101.74   1740 CcmExec

C:\PS> Receive-Job -Job $job

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    68       3     2632        664    29     0.36   1388 ccmsetup
   749      22    21468      19940   203   122.13   3644 communicator
   905       7     2980       2628    34   197.97    424 csrss
  1121      25    28408      32940   174   430.14   3048 explorer

使用 Keep 参数可防止 Receive-Job 删除返回的作业结果。 以下命令显示了对尚未完成的作业使用 Keep 参数的效果。

C:\PS> Receive-Job -Job $job -Keep

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    103       4    11328       9692    56            1176 audiodg
    804      14    12228      14108   100   101.74   1740 CcmExec

C:\PS> Receive-Job -Job $job -Keep

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    103       4    11328       9692    56            1176 audiodg
    804      14    12228      14108   100   101.74   1740 CcmExec
     68       3     2632        664    29     0.36   1388 ccmsetup
    749      22    21468      19940   203   122.13   3644 communicator
    905       7     2980       2628    34   197.97    424 csrss
   1121      25    28408      32940   174   430.14   3048 explorer

等待结果

如果运行的命令需要很长时间才能完成,则可以使用作业对象的属性来确定作业何时完成。 以下命令使用 Get-Job 对象获取当前会话中的所有后台作业。

Get-Job

结果显示在表中。 作业的状态显示在“ 状态 ”列中。

Id Name  PSJobTypeName State    HasMoreData Location  Command
-- ----  ------------- -----    ----------- --------  -------
1  Job1  BackgroundJob Complete True        localhost Get-Process
2  Job2  BackgroundJob Running  True        localhost Get-EventLog -Log ...
3  Job3  BackgroundJob Complete True        localhost dir -Path C:\* -Re...

在这种情况下, State 属性显示作业 2 仍在运行。 如果现在要使用 Receive-Job cmdlet 获取作业结果,则结果将不完整。 可以 Receive-Job 重复使用 cmdlet 来获取所有结果。 使用 State 属性确定作业何时完成。

还可以使用 cmdlet 的 Receive-JobWait 参数。 使用此参数时,cmdlet 在作业完成且所有结果可用之前不会返回命令提示符。

还可以使用 Wait-Job cmdlet 等待作业的任何或所有结果。 Wait-Job 允许等待一个或多个特定作业或所有作业。 以下命令使用 Wait-Job cmdlet 等待 ID 为 10 的作业。

Wait-Job -ID 10

因此,在作业完成之前,将取消 PowerShell 提示符。

还可以等待预先确定的时间段。 此命令使用 Timeout 参数将等待限制为 120 秒。 当时间过期时,命令提示符将返回,但作业继续在后台运行。

Wait-Job -ID 10 -Timeout 120

停止作业

若要停止后台作业,请使用 Stop-Job cmdlet。 以下命令启动一个作业,以获取系统事件日志中的每个条目。 它将作业对象保存在 变量中 $job

$job = Start-Job -ScriptBlock {Get-EventLog -Log System}

以下命令停止作业。 它使用管道运算符 (|) 将变量中的 $job 作业发送到 Stop-Job

$job | Stop-Job

删除作业

若要删除后台作业,请使用 Remove-Job cmdlet。 以下命令删除 变量中的 $job 作业。

Remove-Job -Job $job

调查失败的作业

作业可能由于多种原因而失败。 作业对象包含 一个 Reason 属性,该属性包含有关失败原因的信息。

以下示例在没有所需凭据的情况下启动作业。

$job = Start-Job -ScriptBlock {New-Item -Path HKLM:\Software\MyCompany}
Get-Job $job

Id Name  PSJobTypeName State  HasMoreData  Location  Command
-- ----  ------------- -----  -----------  --------  -------
1  Job1  BackgroundJob Failed False        localhost New-Item -Path HKLM:...

检查 Reason 属性以查找导致作业失败的错误。

$job.ChildJobs[0].JobStateInfo.Reason

在这种情况下,作业失败,因为远程计算机需要显式凭据才能运行命令。 Reason 属性包含以下消息:

连接到远程服务器失败,出现以下错误消息:“访问被拒绝”。

另请参阅