.NET 8调用PowerShell脚本触发执行策略报错问题咨询
我用C#代码调用PowerShell脚本,在.NET 4.7.2项目中正常运行,但同解决方案的.NET 8项目执行时抛出以下异常:
File C:\work\Powershell\SampleAppDotNet8\bin\Debug\net8.0\PS.ps1 cannot be loaded because running scripts is disabled on this system
调用代码:
public void RunScript(string scriptPath, Dictionary<string, object> parameters) { using (var ps = PowerShell.Create()) { ps.AddCommand(scriptPath); foreach (var param in parameters) { ps.AddParameter(param.Key, param.Value); } var results = ps.Invoke(); foreach (var result in results) { Console.WriteLine(result); } if (ps.Streams.Error.Count > 0) { foreach (var error in ps.Streams.Error) { Console.WriteLine($"Error: {error}"); } } } }
我已检查执行策略,结果如下(Windows PowerShell中执行):
PS C:\WINDOWS\system32> Get-ExecutionPolicy -List Scope ExecutionPolicy ----- --------------- MachinePolicy Undefined UserPolicy Undefined Process Undefined CurrentUser Bypass LocalMachine Bypass
两个项目的唯一差异:.NET 8项目引用Microsoft.PowerShell.SDK,而.NET 4.7.2项目引用GAC中的System.Management.Automation.dll(对应Windows PowerShell 5.1)。
PowerShell脚本:
param ( [string]$name, [string]$username, [SecureString]$password ) # Converting SecureString to plain text for display (for demonstration purposes) if ($null -ne $password) { $plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)) } else { # Write-Error "Secure password cannot be null." } # Creating a custom object to return $result = [PSCustomObject]@{ Name = $name Username = $username Password = $plainPassword } # Returning the object Write-Output $result
完整错误信息:
Unhandled exception. System.Management.Automation.PSSecurityException: File C:\work\Powershell\SampleAppDotNet8\bin\Debug\net8.0\PS.ps1 cannot be loaded because running scripts is disabled on this system. ---> System.UnauthorizedAccessException: File C:\work\Powershell\SampleAppDotNet8\bin\Debug\net8.0\PS.ps1 cannot be loaded because running scripts is disabled on this system. --- End of inner exception stack trace --- at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input) at System.Management.Automation.Runspaces.Pipeline.Invoke() at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke) at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync) at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection
1 input, PSDataCollection1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection1 input, PSDataCollection1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke() at PowershellAdvance.PowerShellService.RunScript(String scriptPath, Dictionary2 parameters) in C:\work\Powershell\PowershellParamsResolver\PowerShellService.cs:line 24 at PowershellAdvance.PowerShellScriptRunner.RunAsync(String jsonString, String scriptPath) in C:\work\Powershell\PowershellParamsResolver\PowerShellScriptRunner.cs:line 26 at SampleAppDotNet8.Program.Main(String[] args) in C:\work\Powershell\SampleAppDotNet8\Program.cs:line 26 at SampleAppDotNet8.Program.(String[] args)
请问是否需要调整.NET 8项目中调用PowerShell的方式?
问题根源在于:.NET 8项目引用的Microsoft.PowerShell.SDK默认绑定PowerShell 7+,而.NET 4.7.2项目使用的GAC中的System.Management.Automation.dll对应Windows PowerShell 5.1。这两个PowerShell版本的执行策略是独立配置的,你之前检查的是Windows PowerShell 5.1的执行策略,但PowerShell 7+的执行策略可能仍处于限制状态。
解决方法一:配置PowerShell 7+的执行策略
- 打开PowerShell 7(运行
pwsh.exe) - 执行命令查看当前PowerShell 7的执行策略:
Get-ExecutionPolicy -List
- 设置允许执行脚本的策略,例如针对当前用户设置为Bypass:
Set-ExecutionPolicy Bypass -Scope CurrentUser -Force
解决方法二:在代码中指定执行策略
如果不想修改系统级执行策略,可以在创建PowerShell运行空间时直接指定执行策略,确保脚本能正常加载:
修改后的代码示例:
public void RunScript(string scriptPath, Dictionary<string, object> parameters) { // 创建初始会话状态,设置执行策略 var initialSessionState = InitialSessionState.CreateDefault(); initialSessionState.ExecutionPolicy = ExecutionPolicy.Bypass; // 使用指定的会话状态创建Runspace using (var runspace = RunspaceFactory.CreateRunspace(initialSessionState)) { runspace.Open(); using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand(scriptPath); foreach (var param in parameters) { ps.AddParameter(param.Key, param.Value); } var results = ps.Invoke(); foreach (var result in results) { Console.WriteLine(result); } if (ps.Streams.Error.Count > 0) { foreach (var error in ps.Streams.Error) { Console.WriteLine($"Error: {error}"); } } } } }
注意:代码中设置ExecutionPolicy.Bypass会跳过当前运行空间的执行策略检查,适合测试或受控环境使用。
内容的提问来源于stack exchange,提问作者Vivek Nuna

