我重写了这个来提供一个简单、通用的例子。
运行循环时,我可以使用变量创建多个作业,因此:
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
像在第一个示例中那样将返回的作业保存在数组中,但如果您愿意,也可以这样做。您还可以将每个作业存储在哈希表中,而不是数组中。在哈希表中,键可以是您分配的作业名称,值可以是作业对象本身。