2013-06-03 18 views
6

Tôi có tập lệnh PowerShell sử dụng Sự kiện hẹn giờ không đồng bộ (quy trình nền) để đo thời gian xảy ra một điều kiện nhất định trước khi thực hiện hành động thích hợp. Điều này hoạt động hoàn hảo tốt khi tôi chạy tập lệnh bên trong PowerGUI nhưng khi tôi chạy tập lệnh bằng cách sử dụng dot-sourcing hoặc chạy tập lệnh đó qua tệp bó thì hành động Sự kiện hẹn giờ không kích hoạt.Sự kiện hẹn giờ không đồng bộ PowerShell không hoạt động bên ngoài bảng điều khiển thử nghiệm

Đây là đoạn mã.

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

Vì vậy, khi nó hoạt động, tôi sẽ thấy đầu ra "timeout: XX" cứ 10 giây ghi vào nhật ký. Nhưng điều này chỉ xảy ra khi chạy bên trong trình chỉnh sửa. Khi tôi chạy nó thông qua tập tin thực thi không có gì xảy ra (mặc dù tôi có thể xác nhận vòng lặp while đang xử lý tốt).

Vì vậy, câu hỏi của tôi là tại sao trải nghiệm của tôi lại khác khi tôi chạy tập lệnh bên trong PowerGUI so với dòng lệnh? Suy nghĩ của tôi là có thể có một vấn đề với phạm vi hoặc song song đề nhưng tôi không chính xác chắc chắn vấn đề là gì. Ngoài ra tôi không chạy các sự kiện này bên trong bất kỳ chức năng hoặc vòng lặp nào.

Trả lời

5

Khi gọi tệp tập lệnh, khối tập lệnh $ action được thực thi bằng phạm vi của người gọi (phạm vi chính), không phải phạm vi của tệp kịch bản (phạm vi con). Do đó, các biến được xác định trong tệp kịch bản không có sẵn trong khối tập lệnh $ action, trừ khi chúng được định nghĩa để sử dụng phạm vi toàn cục hoặc có nguồn gốc dấu chấm (sẽ làm cho chúng có sẵn trong phạm vi toàn cục). Xem this wonderful article để biết thêm thông tin.

Giả sử mã bên dưới được chứa trong tệp có tên 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 
} 

Khi gọi từ bảng điều khiển powerhell, khi khối tập lệnh hành động $ được thực hiện, các biến nó sử dụng sẽ không có giá trị.

./test.ps1 

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

Nếu bạn xác định các biến sử dụng trong khối $ action script trước khi bạn gọi kịch bản, các giá trị này sẽ có sẵn khi hành động thực hiện:

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

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

Nếu bạn nằm rải rác mã nguồn kịch bản, các biến được xác định trong tập lệnh sẽ có sẵn trong phạm vi hiện tại, vì vậy khi hành động thực hiện, các giá trị sẽ có sẵn:

. ./test.ps1 

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

Nếu các biến đó đã được khai báo ed trong phạm vi toàn cầu trong file kịch bản:

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

Sau đó, khi khối $ action script thực hiện trong phạm vi phụ huynh, các giá trị sẽ có sẵn:

./test.ps1 

Timer Event Elapsed. Timeout: 100, Location: SomeLocation, SourceIdentifier: SomeIdentifier 
Các vấn đề liên quan