当脚本退出时,您如何自动清除在 PowerShell 脚本中创建的所有事件订阅?

How do you automatically clean up all event subscriptions made in a PowerShell script when that script exits?

我正在设置一个 FileSystemWatcher 来监视文件的变化。这行得通。我还想保留设置它的脚本 运行 直到用户手动终止脚本。这也有效。但是,我还希望 FileSystemWatcher 上的事件订阅在脚本退出时(正常或异常)自动清除。这不起作用,因为事件订阅是会话的一部分,而脚本没有自己的会话。

我尝试在脚本中创建一个新的会话对象并将其用于观察者设置和事件注册,这似乎很好地清理了脚本终止时的事件订阅,但它似乎也导致了我所有的问题控制台 activity 在该子会话中被吞没。

我怎样才能让它在脚本退出时(正常或异常)自动清除事件订阅?(并在保持控制台可见性的同时执行此操作输出。)

如果上下文很重要,这是一个简单的 ZIP 文件构建脚本。我正在尝试向其添加“监视模式”,以便当另一个应用程序更新 ZIP 时,ZIP 将解压缩回创建它的文件夹。因此,该脚本旨在从保持活动状态的 PowerShell 命令行执行,并可能在该脚本运行之前和之后用于其他用途。换句话说,Get-EventSubscriber | Unregister-Event 的强大锤子除了是脚本用户必须自己调用的另一个命令之外,可能有点太强大了。

这是我的脚本的精简版:

$watcher = New-Object System.IO.FileSystemWatcher ".", $fileName -Property @{
    NotifyFilter = [IO.NotifyFilters]::LastWrite
}

Register-ObjectEvent $watcher -EventName Changed -Action {
    Write-Host "File change detected."
    # other things, scripts, etc
}

$watcher.EnableRaisingEvents = $true

Write-Host "Press Ctrl+C to stop watching the file."

while ($true)
{
    if ([Console]::KeyAvailable)
    {
        $keyInfo = [Console]::ReadKey($true)
        if ($keyInfo.Modifiers -eq [ConsoleModifiers]::Control -and $keyInfo.Key -eq [ConsoleKey]::C)
        {
            Exit
        }
    }
    else
    {
        Start-Sleep 0.5
    }
}

尝试以下操作:

$watcher = New-Object System.IO.FileSystemWatcher $pwd, $fileName -Property @{
  NotifyFilter = [IO.NotifyFilters]::LastWrite
}

# Register with a self-chosen source identifier.
$evtJob = Register-ObjectEvent -SourceIdentifier fileWatcher $watcher -EventName Changed -Action {
  Write-Host "File change detected."
  # other things, scripts, etc
}

$watcher.EnableRaisingEvents = $true

Write-Host "Press Ctrl+C to stop watching the file."

try {
  # This blocks execution indefinitely while allowing
  # events to be processed in the -Action script block.
  # Ctrl-C aborts the script by default, which will execute
  # the `finally` block.
  Wait-Event -SourceIdentifier fileWatcher
}
finally {
  # Clean up the event job, and with it the event subscription.
  # Note: If the -Action script block produces output, you
  #       can collect it with Receive-Job first.
  $evtJob | Remove-Job -Force
}