如何扩展 Get-Job“命令”中引用的 Powershell 变量

如何扩展 Get-Job“命令”中引用的 Powershell 变量

我重写了这个来提供一个简单、通用的例子。

运行循环时,我可以使用变量创建多个作业,因此:

foreach ( $n in 1..10 ) {
    start-job { echo $n }
}

这将创建如下作业列表:

Id 名称 PSJobTypeName 状态 HasMoreData 位置 命令
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob 正在运行 True localhost echo $n
3 Job3 BackgroundJob 正在运行 True localhost echo $n
5 Job5 BackgroundJob 正在运行 True localhost echo $n
7 Job7 BackgroundJob 正在运行 True localhost echo $n
9 Job9 BackgroundJob 正在运行 True localhost echo $n
11 Job11 BackgroundJob 正在运行 True localhost echo $n
13 Job13 BackgroundJob 正在运行 True localhost echo $n
15 Job15 BackgroundJob 正在运行 True localhost echo $n
17 Job17 BackgroundJob 正在运行 True localhost echo $n
19 Job19 BackgroundJob 正在运行 True localhost echo $n

我如何知道 Job1 中使用的变量的值?变量列在命令, 但它是未扩大

PS C:\Users\James>(获取工作 1)| fl *


状态:正在运行
HasMoreData : True
状态消息 :
位置:本地主机
命令:echo $n
作业状态信息 : 正在运行
已完成:System.Threading.ManualResetEvent
实例 ID:d000978d-9188-4c96-8563-db068c7dc31b
编号:1
姓名 :Job1
ChildJobs:{Job2}
PSBeginTime:2017 年 11 月 6 日 21:43:31
结束时间:
PSJobTypeName : BackgroundJob
输出 : {}
错误 : {}
进步 : {}
详细:{}
调试 : {}
警告 : {}
信息 : {}

也不是命令在 ChildJob 中扩展:

PS C:\Users\James> (get-job 2) |fl *


状态:已完成
状态消息 :
HasMoreData : True
位置:本地主机
运行空间:System.Management.Automation.RemoteRunspace
调试器:System.Management.Automation.RemotingJobDebugger
IsAsync : True
命令:echo $n
JobStateInfo :已完成
已完成:System.Threading.ManualResetEvent
实例 ID:39bb0735-eecf-4d61-afa2-3db9d14097a4
编号:2
名称 :Job2
子作业:{}
PSBeginTime:2017 年 11 月 6 日 21:43:58
PSEndTime:2017 年 11 月 6 日 21:44:03
PS作业类型名称:
输出:{$null}
错误 : {}
进度:{parent = -1 id = 0 act = 准备首次使用的模块。stat = cur = pct = -1 sec = -1 type =
                完全的}
详细:{}
调试 : {}
警告 : {}
信息 : {}

有人能建议我如何从这些工作中获取扩展变量吗?

------------------------------------------------------------------------------

原始场景:

我已经在循环中执行了一条命令来从一组虚拟机中删除快照:

get-vm | Where-Object -FilterScript { $_.Name -match "TRU-JDF-CMTEST[1-5]"} | ForEach-Object { Get-VMSnapshot -VMName $_.Name | Remove-VMSnapshot -AsJob }

这将创造就业机会,如下例所示:

(Get-Job 4)|fl *


State         : Failed
StatusMessage :
HasMoreData   : True
Location      :
Command       : get-vm | Where-Object -FilterScript { $_.Name -match "TRU-JDF-CMTEST[1-5]" } | ForEach-Object {
                Get-VMSnapshot -VMName $_.Name | Remove-VMSnapshot -AsJob }
JobStateInfo  : Failed
Finished      : System.Threading.ManualResetEvent
InstanceId    : b357f708-59cf-40f1-a07e-a86ddc45985a
Id            : 4
Name          : Job4
ChildJobs     : {}
PSBeginTime   : 04/05/2017 10:33:39
PSEndTime     : 04/05/2017 10:33:39
PSJobTypeName :
Output        : {}
Error         : {Object reference not set to an instance of an object.}
Progress      : {parent = -1 id = 0 act = Virtual Machine Operation stat = Exception cur =  pct = 100 sec = -1 type =
                Completed}
Verbose       : {}
Debug         : {}
Warning       : {}

在此示例中,命令的主要内容如下:

Get-VMSnapshot -VMName $_.Name | Remove-VMSnapshot -AsJob

$_.Name我如何确定这次迭代的价值?

答案1

您不需要扩展传递给后台作业的变量;您只需将其存储在数组或哈希表中以供后续引用。

我尝试了一下您的简化示例,发现局部变量在Start-Job脚本块中可能根本不会扩展 - 除非Using使用修饰符(请参阅Get-Help about_Remote_Variables- 即使对于将在本地计算机上执行的作业也是如此)。为了说明这一点,以下示例创建了四个没有 的后台作业Using和四个有 的后台作业Using

$JobArray = @()

foreach ( $n in 1..4 ) {
    $JobName = $n.ToString()
    Write-Host ("Starting job " + $JobName + "...")
    $JobArray += Start-Job -Name $JobName -ScriptBlock { Write-Host ("Background job " + $JobName) }
}

foreach ( $n in 5..8 ) {
    $JobName = $n.ToString()
    Write-Host ("Starting job " + $JobName + "...")
    $JobArray += Start-Job -Name $JobName -ScriptBlock { Write-Host ("Background job " + $Using:JobName) }
}

Write-Host ("`nWaiting for all jobs to complete...")
Start-Sleep -Seconds 2
$InProgress = $false
do {
    $InProgress = $false
    foreach ( $Job in $JobArray ) {
        if ($Job.JobStateInfo.State -eq "Running") {
            $InProgress = $true
            Start-Sleep -Seconds 1
        }
    }
} while ($InProgress -eq $true)

foreach ( $Job in $JobArray ) {
    Write-Host ("`nJob Name: " + $Job.Name + "  Job ID: " + $Job.ID + "  State: " + $Job.JobStateInfo.state + "  Results on next line...")
    Receive-Job -Job $Job -Keep
}

Write-Host ("`nComplete.  To remove expired jobs run:`n   Remove-Job -State Completed")

上面的示例将每个作业存储在一个数组中,因此作业 #4 可以通过 $JobArray[4] 进行访问。此外,每个作业都根据作业编号(迭代foreach器计数器$n,而不是 PowerShell 分配的作业 ID,可能会有所不同)进行命名。这样就可以通过您为其分配的编号/名称来访问特定作业。

类似的方法可能适用于您的 VM 快照方案。以下内容未经测试,在测试环境中验证之前不应在生产中尝试:

$VmArray = @(get-vm | Where-Object -FilterScript { $_.Name -match "TRU-JDF-CMTEST[1-5]"})
ForEach ($vm in $VmArray) {
    $vmname = $vm.Name
    $snapshot = Get-VMSnapshot -VMName $vmname
    $snapshotname = $snapshot.Name
    Start-Job -Name ($vmname + "-" + $snapshotname) -ScriptBlock { Remove-VMSnapshot -VM $Using:vmname -Name $Using:snapshotname }
}

通过将代码拆分成多行代码块,您有更多机会分配中间局部变量。我没有Start-Job像在第一个示例中那样将返回的作业保存在数组中,但如果您愿意,也可以这样做。您还可以将每个作业存储在哈希表中,而不是数组中。在哈希表中,键可以是您分配的作业名称,值可以是作业对象本身。

相关内容