如何挂钩.NET/WMI事件实现PowerShell模块导入时触发操作
监听PowerShell模块导入事件的可行方案
好问题!我刚好研究过类似的场景,其实PowerShell本身就提供了直接针对模块导入的引擎事件,比你提到的事件日志、Runspace池状态变更要精准得多。下面给你分享两个亲测有效的方案:
一、使用PowerShell引擎内置事件(最推荐)
PowerShell的引擎会在模块加载(手动/自动)时触发两个专属事件,你可以用Register-EngineEvent直接挂钩:
1. 监听手动导入事件(PSModuleLoadedEvent)
当用户执行Import-Module手动导入模块时触发:
# 注册模块手动加载事件 $manualLoadEvent = Register-EngineEvent -SourceIdentifier "ManualModuleLoaded" -Action { $moduleInfo = $EventArgs.ModuleInfo Write-Host "[手动导入] 模块: $($moduleInfo.Name) | 版本: $($moduleInfo.Version) | 路径: $($moduleInfo.Path)" # 在这里添加你的条件判断和自定义操作 if ($moduleInfo.Name -match "^AzureAD|ExchangeOnlineManagement$") { Write-Host "检测到目标模块,执行指定动作..." # 示例:记录日志、调用自定义函数等 # Log-ModuleImport -Module $moduleInfo # Execute-MyCustomTask } }
2. 监听自动导入事件(PSModuleAutoLoadedEvent)
当调用某个未加载模块的命令,导致PowerShell自动导入模块时触发:
# 注册模块自动加载事件 $autoLoadEvent = Register-EngineEvent -SourceIdentifier "AutoModuleLoaded" -Action { $moduleInfo = $EventArgs.ModuleInfo Write-Host "[自动导入] 模块: $($moduleInfo.Name) | 版本: $($moduleInfo.Version) | 触发命令: $($EventArgs.CommandName)" # 同样可以添加条件过滤逻辑 if ($moduleInfo.Name -eq "PSScriptAnalyzer") { Write-Host "自动导入了目标模块,执行操作..." } }
取消监听的方法
如果不再需要监听,记得注销事件:
Unregister-Event -SourceIdentifier "ManualModuleLoaded" Unregister-Event -SourceIdentifier "AutoModuleLoaded"
二、关于你提到的其他方案的补充
- 模块事件日志:默认情况下,PowerShell不会把模块导入操作写入事件日志,除非模块本身有自定义的日志逻辑,所以这个方案不够通用,不推荐。
- Runspace池状态变更:这个事件的范围太宽泛,无法精准定位到“模块导入”这个动作,会产生大量无关触发,实用性不高。
额外注意事项
- 事件的
Action脚本块会在单独的Runspace中执行,如果你需要和主Runspace交互,可能需要用Get-Variable结合-Scope Global来传递数据。 - 如果是在脚本中运行,要保持PowerShell会话处于打开状态,否则事件会失效;如果需要持续监听,可以在脚本末尾添加
Wait-Event来阻塞会话。
内容的提问来源于stack exchange,提问作者Chris Magnuson
相关产品推荐
相关产品推荐

