2013-06-03 11 views
6

Ho uno script PowerShell che utilizza un evento timer asincrono (processo in background) per misurare la durata di una determinata condizione prima di intraprendere l'azione appropriata. Funziona perfettamente quando eseguo lo script all'interno di PowerGUI, ma quando eseguo lo script utilizzando dot-sourcing o lo eseguo tramite un file batch, le azioni dell'evento timer non vengono attivate.Eventi timer asincroni PowerShell non funzionanti al di fuori della console di test

Ecco uno snippet di codice.

$timer = New-Object System.Timers.Timer 
$timer.Interval = 10000 
$timer.AutoReset = $true 
$timeout = 0 

$action = { 
    "timeout: $timeout" | Add-Content $loglocation 
    <more stuff here> 
    $timer.stop() 
} 
$start = Register-ObjectEvent -InputObject $timer -SourceIdentifier TimerElapsed -EventName Elapsed -Action $action 

$timer.start() 

while(1) 
{ 
    <do some testing here> 
} 

Quindi quando funziona, vedrò l'output "timeout: XX" ogni 10 secondi scritto nel registro. Ma questo succede solo quando viene eseguito all'interno dell'editor. Quando lo eseguo tramite file batch non succede nulla (anche se posso confermare che il ciclo while sta funzionando bene).

Quindi la mia domanda è perché la mia esperienza è diversa quando eseguo lo script all'interno di PowerGUI rispetto alla riga di comando? Il mio pensiero è che potrebbe esserci un problema con l'ambito o i thread paralleli, ma non sono esattamente sicuro di quale sia il problema. Inoltre non sto eseguendo questi eventi all'interno di alcuna funzione o loop.

risposta

5

Quando si chiama il file di script, il blocco di script $ action viene eseguito utilizzando l'ambito del chiamante (ambito padre), non l'ambito del file di script (ambito secondario). Pertanto, le variabili definite all'interno del file di script non sono disponibili all'interno del blocco di script $ action, a meno che non siano definite per utilizzare l'ambito globale o dot-sourced (che le renderà disponibili nell'ambito globale). Vedere this wonderful article per ulteriori informazioni.

Si supponga che il codice riportato di seguito sia contenuto in un file denominato test.ps1.

$timer = New-Object System.Timers.Timer 
$timer.Interval = 10000 
$timer.AutoReset = $false 

$timeout = 100 
$location = 'SomeLocation' 
$sourceIdentifier = 'SomeIdentifier' 

$action = { 
Write-Host "Timer Event Elapsed. Timeout: $timeout, Location: $location, SourceIdentifier: $sourceIdentifier" 
$timer.stop() 
Unregister-Event $sourceIdentifier 
} 

$start = Register-ObjectEvent -InputObject $timer -SourceIdentifier $sourceIdentifier -EventName Elapsed -Action $action 

$timer.start() 

while(1) 
{ 
Write-Host "Looping..." 
Start-Sleep -s 5 
} 

Quando si chiama dalla console PowerShell, quando viene eseguito il blocco di script di azione $, le variabili che utilizza avranno alcun valore.

./test.ps1 

Timer Event Elapsed. Timeout: , Location: , SourceIdentifier: 

Se si definiscono le variabili utilizzate nel blocco di $ script di azione prima di chiamare lo script, i valori saranno disponibili quando l'azione viene eseguita:

$timeout = 5; $location = "SomeLocation"; $sourceIdentifier = "SomeSI" 
./test.ps1 

Timer Event Elapsed. Timeout: 5, Location: SomeLocation, SourceIdentifier: SomeSI 

Se dot-sorgente dello script, le variabili definite all'interno dello script sarà disponibile nell'ambito corrente, in modo che quando l'azione viene eseguita, i valori saranno disponibili:

. ./test.ps1 

Timer Event Elapsed. Timeout: 100, Location: SomeLocation, SourceIdentifier: SomeIdentifier 

Se le variabili sarebbero state declar Ed in ambito globale nel file di script:

$global:timeout = 100 
$global:location = 'SomeLocation' 
$global:sourceIdentifier = 'SomeIdentifier' 

Poi, quando il blocco di $ action script viene eseguito nel campo di applicazione genitore, i valori saranno disponibili:

./test.ps1 

Timer Event Elapsed. Timeout: 100, Location: SomeLocation, SourceIdentifier: SomeIdentifier 
Problemi correlati