如何使用PowerShell拦截Windows关机信号并在关机前执行写入操作
PowerShell拦截Windows关机信号并执行预设写入操作实现方案
实现原理
Windows发起关机、重启、注销流程时,会向所有顶层窗口广播WM_QUERYENDSESSION系统消息,同时会触发WMI系统事件。你可以通过PowerShell监听上述两类通知,在系统执行关机动作前运行自定义写入逻辑。
实现方案
方案1:WMI事件监听(简单易用,适合轻量写入操作)
无需引入额外依赖,直接注册系统级事件监听即可实现:
- 首先定义你需要执行的写入逻辑,示例为写入关机日志到本地文件:
function Invoke-PreShutdownTask { # 替换为你自己的写入逻辑,支持写入文件、注册表、数据库等任意操作 $log = "关机操作触发时间:$([DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss'))" $log | Out-File -Path "C:\ShutdownRecord.log" -Append -Encoding UTF8 }
- 注册关机事件监听,事件触发时自动执行写入操作:
# 注册系统关机/重启/注销事件查询 $shutdownQuery = "SELECT * FROM Win32_ComputerShutdownEvent" Register-WmiEvent -Query $shutdownQuery -Action { Invoke-PreShutdownTask } | Out-Null # 防止脚本进程自动退出,保持后台监听 while ($true) { Start-Sleep -Seconds 30 }
方案2:WinForm消息监听(稳定可靠,适合耗时写入操作)
如果你的写入操作耗时较长,建议使用该方案,系统会默认等待消息处理完成再推进关机流程,无需主动取消关机:
Add-Type -AssemblyName System.Windows.Forms # 定义写入逻辑 function Invoke-PreShutdownTask { $log = "关机操作触发时间:$([DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss'))" $log | Out-File -Path "C:\ShutdownRecord.log" -Append -Encoding UTF8 # 模拟耗时操作,可根据实际场景调整 Start-Sleep -Seconds 10 } # 创建隐藏窗口用于接收系统消息 $hiddenForm = New-Object System.Windows.Forms.Form $hiddenForm.Visible = $false $hiddenForm.ShowInTaskbar = $false # 绑定系统关闭事件处理逻辑 $hiddenForm.Add_Closing({ param($sender, $eventArgs) # 仅处理系统关机触发的关闭请求 if ($eventArgs.CloseReason -eq [System.Windows.Forms.CloseReason]::WindowsShutDown) { # 先执行写入操作 Invoke-PreShutdownTask } }) # 启动消息循环保持监听 [System.Windows.Forms.Application]::Run($hiddenForm)
注意事项
- 所有脚本必须以管理员权限运行,否则无法注册系统级事件、也无法读取关机事件通知
- 写入操作的目标路径需要确保运行脚本的账号有对应读写权限,避免操作失败
- 如需长期生效,可将脚本添加到Windows任务计划程序,设置开机自动以管理员权限启动
- 如果写入操作耗时超过10秒,建议优先使用方案2,避免被系统强制终止进程导致写入不完整
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

