.NET 5插件架构中调用PowerShell的Get-Disk cmdlet失败问题
问题根因
你遇到的报错是.NET插件的AssemblyLoadContext(ALC)隔离机制和PowerShell SDK的依赖加载逻辑冲突导致的:
- 按照官方插件教程实现的加载逻辑会给每个插件分配独立的ALC,插件引用的所有NuGet包默认都会在这个独立ALC中加载,和主程序的默认ALC完全隔离
- Storage是Windows内置的CIM类型PowerShell模块,加载时会依赖全局上下文中的
System.Management.Automation、Microsoft.PowerShell.*等核心程序集的类型定义 - 插件独立ALC中加载的PowerShell核心程序集和系统模块预期的默认ALC中的程序集属于不同实例,对应类型无法被识别,就会触发getter方法参数不匹配的报错,进而导致Storage模块加载失败
- 你在插件外部调用能正常运行,是因为直接调用时PowerShell SDK是加载在主程序默认ALC中的,类型匹配不存在隔离问题。
解决方案
方案1:调整插件ALC的加载逻辑,共享PowerShell相关程序集
重载你实现的插件ALC类的Load方法,遇到PowerShell相关程序集时直接从主程序的默认ALC加载,不要在插件独立ALC中重复加载:protected override Assembly Load(AssemblyName assemblyName) { // 匹配所有PowerShell核心程序集,走默认上下文加载 if (assemblyName.Name.StartsWith("Microsoft.PowerShell") || assemblyName.Name.StartsWith("System.Management.Automation")) { return AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName); } // 其余插件专属程序集保留原有加载逻辑即可 // ... }注意主项目需要和插件引用相同版本的
Microsoft.PowerShell.SDKNuGet包,避免版本不匹配的加载错误。方案2:指定PowerShell使用全局运行空间
创建PowerShell实例时指定使用当前进程的默认运行空间,绕开插件独立上下文的加载限制,适合没有多线程并发调用PowerShell的场景:// 修改实例创建参数即可 using (PowerShell ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) { ps.AddScript("Import-Module Storage; Get-Disk"); ps.Invoke(); Console.WriteLine(string.Join(", ", ps.Streams.Error)); }方案3:绕过PowerShell模块直接调用CIM接口
如果仅需要获取磁盘等系统硬件信息,可以直接引用Microsoft.Management.InfrastructureNuGet包调用CIM接口,完全避免PowerShell模块加载的相关问题,性能也更优。
内容的提问来源于stack exchange,提问作者SuperJMN
相关产品推荐
相关产品推荐

