{ ... }
- это блок сценария (литерал) - повторно используемый фрагмент кода PowerShell, который можно выполнять по требованию (например, указатель функции или делегат на других языках).
Передавая такой блок, хранящийся в переменной $action
, в Register-ObjectEvent -Action
, PowerShell вызывает его всякий раз, когда происходит интересующее событие, и делает это в области действия child вызывающего кода.
Следовательно, ваш вызывающий код не видит переменные, созданные внутри блока, так как они являются локальными для этого блока.
Для получения дополнительной информации о областях в PowerShell см. Нижний раздел этот ответ .
Хотя PowerShell позволяет создавать и изменять переменные также в других областях, это не вариант с Register-ObjectEvent -Action
, поскольку блок сценария выполняется в dynamici c модуле , который не имеет доступа к области видимости вызывающего абонента, только к global scope.
# !! This works, but is ill-advised.
$global:terminateFlag = RunFunctions $path $changeType $logPath
Однако лучше избегать с использованием глобальной области видимости. , потому что глобальные переменные задерживаются даже после выхода из скрипта (они сеанс -глобальный).
Лучшее решение состоит в следующем:
сделать блок сценария действия output значением для вызывающего абонента.
сделать так, чтобы вызывающий получил этот вывод через Receive-Job
, используя задание события, которое Register-ObjectEvent -Action
возвращает.
Вот упрощенный автономный пример, демонстрирующий технику:
Он устанавливает наблюдатель, подключает обработчик события и создает файл, который запускает событие наблюдателя.
try {
# Specify the target folder: the system's temp folder in this example.
$dir = (Get-Item -EA Ignore temp:).FullName; if (-not $dir) { $dir = $env:TEMP }
# Create and initialize the watcher.
$watcher = [System.IO.FileSystemWatcher] @{
Filter = '*.tmp'
Path = $dir
}
# Define the action script block (event handler).
$action = {
# Print the event data to the host.
Write-Host "Event raised:`n$($EventArgs | Format-List | Out-String)"
$terminateFlag = $true
# *Return* a value that indicates whether watching should be stopped.
# This value is later retrieved via Receive-Job.
return $terminateFlag
}
# Subscribe to the watcher's Created events, which returns an event job.
# This indefinitely running job receives the output from the -Action script
# block whenever the latter is called after an event fires.
$eventJob = Register-ObjectEvent $watcher Created -Action $action
# Start watching:
# Note: Not strictly necessary, because, curiously,
# Register-ObjectEvent has aleady done this for us.
$watcher.EnableRaisingEvents = $true
# Using an aux. background job, create a sample file that will trigger the
# watcher, after a delay.
$tempFile = Join-Path $dir "$PID.tmp"
$auxJob = Start-Job { Start-Sleep 3; 'hi' > $using:tempFile }
Write-Host "Watching $dir for creation of $($watcher.Filter) files..."
# Wait in a loop until the action block is run in response to an event and
# produces $true as output to signal the intent to terminate, via Receive-Job.
while ($true -ne (Receive-Job $eventJob)) {
write-host . -NoNewline
Start-Sleep -Milliseconds 500 # sleep a little
}
}
finally {
# Clean up.
# Dispose of the watcher.
$watcher.Dispose()
# Remove the event job (and with it the event subscription).
$eventJob | Remove-Job -Force
# Clean up the helper job.
Remove-Job -ea Ignore -Force $auxJob
# Remove the temp. file
Remove-Item -ea Ignore $tempFile
}