2013-06-03 53 views
6

我有一個PowerShell腳本,它使用一個異步計時器事件(後臺進程)來測量在採取適當操作之前發生了特定條件的時間。 當我在PowerGUI中運行腳本時,這是工作得很好,但是當我使用點源運行腳本或通過批處理文件運行它時,Timer事件操作未觸發。PowerShell異步計時器事件不能在測試控制檯以外工作

這是一段代碼片段。

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

所以,當它工作時,我會看到每10秒寫入日誌的「超時:XX」輸出。但是這隻有在編輯器中運行時纔會發生。當我通過批處理文件運行它時沒有任何反應(儘管我可以確認while循環處理正常)。

所以我的問題是爲什麼我的經驗不同,當我在PowerGUI中運行腳本與通過命令行?我的想法是可能存在一個問題或者並行線程,但我不確定問題是什麼。此外,我沒有在任何函數或循環中運行這些事件。

回答

5

調用腳本文件時,使用調用者(父範圍)的範圍執行$ action腳本塊,而不是腳本文件的範圍(子範圍)。因此,腳本文件中定義的變量在$ action腳本塊中不可用,除非它們被定義爲使用全局範圍或點源(使其在全局範圍內可用)。有關更多信息,請參閱this wonderful article

假設下面的代碼包含在名爲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 
} 

從powershell控制檯調用時,執行$ action腳本塊時,它使用的變量將沒有值。

./test.ps1 

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

如果定義在$動作腳本塊用於調用腳本之前的變量,該值將作爲可用的時候,動作執行:

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

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

如果你點源腳本,在腳本中定義的變量將在目前的範圍變得可用,所以操作執行時,該值將作爲可用:

. ./test.ps1 

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

如果變量會一直declar編輯在腳本文件中的全局範圍:

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

然後當$動作腳本塊在父範圍內執行,該值將作爲可用:

./test.ps1 

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