在自定义C# PowerShell CmdLet中使用Microsoft.Data.SqlClient遇版本冲突
问题背景
在基于.NET Framework 4.7.2开发自定义PowerShell Cmdlet时,使用Microsoft.Data.SqlClient遇到版本冲突:SqlClient要求加载System.Memory 4.0.1.1,但项目因其他NuGet包依赖已升级System.Memory至最新版本,常规app.config配置无效,报错如下:
Could not load file or assembly 'System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.
相关Cmdlet代码:
public class CmdLetEnvironment { public static bool Connected = false; [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommunications.Connect, "RDTest")] public class RDEnvironmentConnectCommand : System.Management.Automation.PSCmdlet { protected override void ProcessRecord() { try { SqlConnection conn = new SqlConnection("Data Source=localhost\\SQLEXPRESS;Initial Catalog=TestLocalOMA1;Integrated Security=True;Encrypt=False"); conn.Open(); } catch(Exception ex) { throw ex.InnerException; } } } }
解决方案
1. 正确配置程序集绑定重定向(核心方案)
PowerShell环境下,程序集绑定重定向需满足两个条件:配置文件与Cmdlet程序集同名、放在同一目录。例如你的Cmdlet输出dll为RDTestCmdlet.dll,则配置文件需命名为RDTestCmdlet.dll.config,内容添加以下绑定规则:
<?xml version="1.0" encoding="utf-8"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> <!-- 将旧版本范围重定向到你项目实际引用的System.Memory版本 --> <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.2" /> <!-- 替换为你当前使用的版本号 --> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
注意:newVersion需替换为你项目中实际安装的System.Memory版本号(可在NuGet包管理器中查看)。
2. 调整Microsoft.Data.SqlClient版本
检查当前使用的Microsoft.Data.SqlClient版本,尝试升级到v2.1.0及以上版本(这类版本对System.Memory的依赖兼容性更强),或降级到既兼容System.Memory 4.0.1.1、又不影响其他NuGet包的版本。
3. 强制复制System.Memory到输出目录
在项目的System.Memory引用属性中,将复制到输出目录设置为始终复制,确保对应的dll文件被复制到Cmdlet的输出目录,配合绑定重定向配置使用。
额外调试建议
- 若使用PowerShell 5.x,需确保Cmdlet程序集和配置文件放在PowerShell能加载的路径,或通过
Import-Module指定完整路径加载。 - 避免直接抛出InnerException,建议在Cmdlet中使用
WriteError输出错误信息,便于调试:
catch(Exception ex) { WriteError(new ErrorRecord(ex.InnerException ?? ex, "ConnectionFailed", ErrorCategory.ConnectionError, null)); }
内容的提问来源于stack exchange,提问作者Oliver M.

