2

Я переписал это, чтобы предоставить простой, общий пример.

При запуске цикла я могу создать несколько заданий, используя переменную, таким образом:

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

Это создает список заданий следующим образом:

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
1      Job1            BackgroundJob   Running       True            localhost             echo $n
3      Job3            BackgroundJob   Running       True            localhost             echo $n
5      Job5            BackgroundJob   Running       True            localhost             echo $n
7      Job7            BackgroundJob   Running       True            localhost             echo $n
9      Job9            BackgroundJob   Running       True            localhost             echo $n
11     Job11           BackgroundJob   Running       True            localhost             echo $n
13     Job13           BackgroundJob   Running       True            localhost             echo $n
15     Job15           BackgroundJob   Running       True            localhost             echo $n
17     Job17           BackgroundJob   Running       True            localhost             echo $n
19     Job19           BackgroundJob   Running       True            localhost             echo $n

Как я могу сказать значение переменной, используемой в Job1? Переменная указана в команде, но она не раскрывается:

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


State         : Running
HasMoreData   : True
StatusMessage :
Location      : localhost
Command       :  echo $n
JobStateInfo  : Running
Finished      : System.Threading.ManualResetEvent
InstanceId    : d000978d-9188-4c96-8563-db068c7dc31b
Id            : 1
Name          : Job1
ChildJobs     : {Job2}
PSBeginTime   : 11/06/2017 21:43:31
PSEndTime     :
PSJobTypeName : BackgroundJob
Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}
Information   : {}

Также команда не расширена в ChildJob:

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


State         : Completed
StatusMessage :
HasMoreData   : True
Location      : localhost
Runspace      : System.Management.Automation.RemoteRunspace
Debugger      : System.Management.Automation.RemotingJobDebugger
IsAsync       : True
Command       :  echo $n
JobStateInfo  : Completed
Finished      : System.Threading.ManualResetEvent
InstanceId    : 39bb0735-eecf-4d61-afa2-3db9d14097a4
Id            : 2
Name          : Job2
ChildJobs     : {}
PSBeginTime   : 11/06/2017 21:43:58
PSEndTime     : 11/06/2017 21:44:03
PSJobTypeName :
Output        : {$null}
Error         : {}
Progress      : {parent = -1 id = 0 act = Preparing modules for first use. stat =   cur =  pct = -1 sec = -1 type =
                Completed}
Verbose       : {}
Debug         : {}
Warning       : {}
Information   : {}

Может кто-нибудь предложить, как я могу получить расширенные переменные из этих заданий?

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

Оригинальный сценарий:

Я выполнил команду в цикле, чтобы удалить снимки из нескольких виртуальных машин:

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 ответ1

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, который может варьироваться). Это позволяет получить доступ к определенной работе по номеру / имени, которое вы ей присвоили.

Аналогичный подход может быть применим к вашему сценарию моментального снимка виртуальной машины. Следующее является НЕПРОВЕРЕННЫМ и не должно предприниматься в производственной среде, пока не будет проверено в среде тестирования:

$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 в массиве, как я делал в моем первом примере, но вы можете сделать это, если хотите. Вы также можете хранить каждое задание в хеш-таблице, а не в массиве. В хеш-таблице ключом может быть назначенное вами имя задания, а значением может быть сам объект задания.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .