Como expandir a variável Powershell referenciada em Get-Job “Command”

2

Eu reescrevi isso para fornecer um exemplo simples e genérico.

Ao executar um loop, posso criar várias tarefas usando uma variável, assim:

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

Isso cria uma lista de trabalhos da seguinte forma:

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

Como posso saber o valor da variável usada no Job1? A variável está listada no Comando , mas não é expandida :

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   : {}

Nem o Comando é expandido no 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   : {}

Alguém pode sugerir como posso obter as variáveis expandidas desses trabalhos?

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

Cenário original:

Eu executei um comando dentro de um loop para remover instantâneos de um monte de VMs:

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

Isso cria trabalhos, conforme o exemplo abaixo:

(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       : {}

Neste exemplo, a carne do comando é listada como:

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

Como posso determinar o valor de $_.Name nesta iteração?

    
por James Finch 04.05.2017 / 11:47

1 resposta

1

Você não precisa expandir a variável passada para o job em segundo plano; você só precisa armazená-lo em uma matriz ou hashtable para referência subseqüente.

Brinquei com o seu exemplo simplificado e descobri que variáveis locais podem não se expandir em um bloco de script Start-Job - a menos que o modificador Using seja utilizado (veja Get-Help about_Remote_Variables - mesmo para trabalhos que serão executados no computador local). Para ilustrar, o exemplo a seguir cria quatro tarefas em segundo plano sem Using e mais quatro com 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")

O exemplo acima, armazena cada trabalho em uma matriz, assim o trabalho nº 4 pode ser acessado como $ JobArray [4]. Além disso, cada trabalho é nomeado de acordo com o número do trabalho (o foreach contador do iterador $n , não o ID do trabalho atribuído pelo PowerShell, que pode variar). Isso permite o acesso a um trabalho específico pelo número / nome que você atribuiu a ele.

Uma abordagem semelhante pode ser aplicável ao cenário de snapshot da sua VM. O seguinte é UNTESTED e não deve ser tentado em produção até ser verificado em um ambiente de teste:

$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 }
}

Ao dividir as coisas em blocos de código de várias linhas, você tem mais oportunidade de atribuir variáveis locais intermediárias. Eu não preservei o trabalho retornado por Start-Job em uma matriz, como fiz no meu primeiro exemplo, mas você poderia fazer isso se desejar. Você também pode armazenar cada trabalho em um hashtable, em vez de em um array. No hashtable, a chave pode ser o nome do trabalho que você atribuiu e o valor pode ser o próprio objeto de trabalho.

    
por 31.08.2018 / 11:18

Tags