能否拦截交互式Shell输入的所有命令?PowerShell命令拦截及计时咨询
实现交互式PowerShell命令拦截与超时通知
完全可以做到!在PowerShell的交互式环境里,咱们可以借助PSReadLine的事件钩子和自定义prompt函数来实现这个需求,刚好能满足你给每条命令计时、超时弹通知的要求。
核心思路
PowerShell默认使用PSReadLine模块处理交互式输入,它提供了CommandAcceptedAction事件——这个事件会在你按下回车执行命令的瞬间触发。我们可以利用它记录命令的开始时间,然后在每次显示新提示符之前(也就是命令执行完成后),计算执行时长,超过30秒就用BurntToast发送通知。
具体实现步骤
安装BurntToast模块(如果还没装)
首先需要安装发送通知的依赖模块,在PowerShell里运行:Install-Module -Name BurntToast -Scope CurrentUser -Force(如果提示信任仓库,输入
Y确认即可)注册命令开始时间的事件钩子
这段代码会在你每次执行命令时记录开始时间:# 定义全局变量存储命令开始时间 $script:commandStartTime = $null # 注册PSReadLine的命令接受事件 Register-EngineEvent -SourceIdentifier PSReadLine.CommandAcceptedAction -Action { $script:commandStartTime = Get-Date } | Out-Null重写
prompt函数实现计时与通知prompt函数是PowerShell每次显示命令提示符前都会运行的函数,我们在这里计算上一条命令的执行时长并触发通知:function prompt { # 检查是否有记录的命令开始时间 if ($script:commandStartTime) { $executionDuration = (Get-Date) - $script:commandStartTime # 判断是否超过30秒阈值 if ($executionDuration.TotalSeconds -ge 30) { # 格式化时长(保留2位小数) $formattedTime = [math]::Round($executionDuration.TotalSeconds, 2) # 发送BurntToast通知 New-BurntToastNotification -Text "命令执行完成", "总耗时: $formattedTime 秒" } # 重置开始时间,避免重复触发通知 $script:commandStartTime = $null } # 保留默认提示符的行为(显示当前路径) "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) " }
让设置永久生效
如果你希望每次打开PowerShell都自动启用这个功能,可以把上面的代码添加到你的PowerShell配置文件中:
- 运行
notepad $PROFILE打开配置文件(如果文件不存在,PowerShell会提示你创建) - 将代码粘贴到文件中,保存后关闭
- 下次启动PowerShell时,这个功能就会自动生效
注意事项
- 这个方案针对前台执行的交互式命令,如果是后台作业(比如加
&或者Start-Job),计时会不准确,因为后台作业会立即返回,实际执行在后台。如果需要支持后台作业,需要额外跟踪作业的执行状态。 - 如果你的PowerShell版本较旧(比如5.1之前),可能需要手动安装PSReadLine模块:
Install-Module -Name PSReadLine -Scope CurrentUser -Force
内容的提问来源于stack exchange,提问作者millimoose
相关产品推荐
相关产品推荐

