Using the Register-EnginerEvent -Forward and New-Event I am trying to forward object events from a remote server to the host server however it does not seem to work.
To prove the theory, tried the below simple code which does work:
$TargetServer = 'localhost'
Register-EngineEvent -SourceIdentifier TimerEventOccured -Action {
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - $($event.MessageData) received..." -ForegroundColor Green
} | Out-Null
$TimerScriptBlock = {
Register-EngineEvent -SourceIdentifier TimerEventOccured -Forward | Out-Null
$Count = 1
while($Count -lt 3) {
New-Event -SourceIdentifier TimerEventOccured -MessageData 'Timertriggered'
Start-Sleep -Seconds 5
$Count = 1
}
}
$RemoteTimerScriptBlockJob = Invoke-Command -ComputerName $TargetServer -ScriptBlock $TimerScriptBlock -AsJob
while($RemoteTimerScriptBlockJob.State -in @('NotStarted','Running')) {
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - remote timer job still running"
Start-Sleep -Seconds 5
}
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - remote timer job complete"
...where as the below adding Register-ObjectEvent, which is what I want to achieve, doesn't.
$TargetServer = 'localhost'
Register-EngineEvent -SourceIdentifier TimerEventOccured -Action {
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - $($event.MessageData) received..." -ForegroundColor Green
} | Out-Null
$TimerScriptBlock = {
Register-EngineEvent -SourceIdentifier TimerEventOccured -Forward | Out-Null
$timer = New-Object timers.timer
$timer.Enabled = $true
$timer.Interval = 3000
Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier thetimer -Action $action {
New-Event -SourceIdentifier TimerEventOccured -MessageData 'Timertriggered'
}
$timer.start()
Start-Sleep -Seconds 15 #just wait long enough for timer events to trigger a few times
}
$RemoteTimerScriptBlockJob = Invoke-Command -ComputerName $TargetServer -ScriptBlock $TimerScriptBlock -AsJob
while($RemoteTimerScriptBlockJob.State -in @('NotStarted','Running')) {
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - remote timer job still running"
Start-Sleep -Seconds 5
}
Write-Host "$(Get-Date -format "dd-MM-yyyy hh:mm:ss tt") - remote timer job complete"
Could you please help? Thanks.
Update:
Please note, I could directly forward the timer-event to the source server without needing the engine-event as the intermediary. But above timer event was only used to illustrate the point here. The real work I am dealing with is to monitor Windows Event log for certain event ids (which has become quite complex to share here).
So, if I were to use -forward directly on the Eventlog listener Object then it will create a lot of traffic from target servers to host session (i.e. every event written will be dispatched as opposed to the only ones I am after). I want to be able to process the triggered event first on the remote server itself (to match the input eventIDs) and then forward the filtered event through engine event, which is where I am stuck.
CodePudding user response:
In short: Register-ObjectEvent
isn't the problem in your case - it is the fact that you use a single Start-Sleep
call after which you exit immediately, which causes most of the events to be lost.
When you suspend PowerShell's own foreground thread with Start-Sleep
, you also suspend its event processing.
Specifically, this plays out as follows in your case:
While
Start-Sleep
runs, events are queued - the immediate side effect of which is that your events aren't processed in a timely fashion.When
Start-Sleep
ends and the foreground thread regains control, the event queue starts getting processed, but since the script block ends right away, only an - unpredictable - subset of the queued events gets processed before overall execution of the remote script block ends. Seemingly, PowerShell doesn't ensure that queued events are processed before exiting.
Thus, if you break you single Start-Sleep -Seconds 15
call into multiple ones, giving PowerShell time to process events in between, your code should work:
1..3 | ForEach-Object { Start-Sleep -Seconds 5 }
Again, note that there's no guarantee that if events still happen to be queued afterwards that they will be processed before exiting.