无法从C#程序加载PowerShell脚本:修改执行策略仍报错
我太懂你这种改了半天执行策略还是踩坑的憋屈感!明明把ExecutionPolicy改成RemoteSigned,甚至把MachinePolicy设成Bypass、组策略也开了脚本运行权限,结果调用时还是弹出那个烦人的错误:
System.Management.Automation.PSSecurityException: 'File Path\TestADUser.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at https://go.microsoft.com/fwlink/?LinkID=135170.'
先看看你贴的代码:
你的C#调用代码
public string Test() { StringBuilder sb = new StringBuilder(); string script = @"Path\TestADUser.ps1"; var FirstName = "Test1234"; PowerShell shell = PowerShell.Create(); shell.AddCommand(script, false); shell.AddParameter("FirstName", FirstName); Collection<PSObject> results = shell.Invoke(); Collection<ErrorRecord> errors = shell.Streams.Error.ReadAll(); if (errors.Count > 0) { foreach (ErrorRecord error in errors) { sb.AppendLine(error.ToString()); } } else { foreach (PSObject result in results) { sb.AppendLine(result.ToString()); } } return sb.ToString(); }
对应的PowerShell脚本TestADUser.ps1
param( [parameter(position=0)] [string]$FirstName) ##Output Write-Output $FirstName
问题其实出在C#调用PowerShell的上下文隔离上:很多人容易忽略32位/64位PowerShell的执行策略是分开存储的——比如你在64位PowerShell里改了策略,但你的C#程序跑在32位环境下,那等于白改!而且系统级的策略有时候会被进程级的上下文覆盖。
给你两个靠谱的解决办法:
方法一:匹配程序架构设置执行策略
- 先确认你的C#程序是32位还是64位运行(去项目属性里看「平台目标」)
- 如果是64位,打开普通PowerShell,执行:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force - 如果是32位,找到
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe打开,执行上面同样的命令
方法二:在C#代码里指定进程级执行策略(更推荐)
这种方法不用改系统全局设置,只对当前PowerShell进程生效,安全又省心。修改你的C#代码,在添加脚本命令之前,先加一行设置执行策略的逻辑:
public string Test() { StringBuilder sb = new StringBuilder(); string script = @"Path\TestADUser.ps1"; var FirstName = "Test1234"; PowerShell shell = PowerShell.Create(); // 新增:设置当前PowerShell进程的执行策略为RemoteSigned shell.AddCommand("Set-ExecutionPolicy") .AddParameter("ExecutionPolicy", "RemoteSigned") .AddParameter("Scope", "Process") .AddParameter("Force"); // 继续原来的脚本调用逻辑 shell.AddCommand(script, false); shell.AddParameter("FirstName", FirstName); Collection<PSObject> results = shell.Invoke(); Collection<ErrorRecord> errors = shell.Streams.Error.ReadAll(); if (errors.Count > 0) { foreach (ErrorRecord error in errors) { sb.AppendLine(error.ToString()); } } else { foreach (PSObject result in results) { sb.AppendLine(result.ToString()); } } return sb.ToString(); }
解释下:Scope设为Process意味着这个执行策略只在当前PowerShell会话里生效,进程关闭后就失效,完全不会影响系统其他设置,不用担心安全风险。
试一下这两个方法,应该就能搞定你的问题了!
内容的提问来源于stack exchange,提问作者Morten Godrim Jensen

