C# 为什么不能在C中作为常规进程调用Powershell#
想知道Powershell是否需要从C#代码调用一个特殊的库(位于System.Management.Automation NS中)?我有以下代码:C# 为什么不能在C中作为常规进程调用Powershell#,c#,powershell,C#,Powershell,想知道Powershell是否需要从C#代码调用一个特殊的库(位于System.Management.Automation NS中)?我有以下代码: Process p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError =
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
string trackerPath = "C:\\Users\\bernam\\Downloads\\test_scripts\\test_scripts\\Mindaugas_Scripts\\test.ps1";
p.StartInfo.FileName = "Powershell.exe";
p.StartInfo.Arguments = " -file " + trackerPath;
Console.WriteLine(p.StartInfo.FileName + p.StartInfo.Arguments);
p.Start();
string output = p.StandardOutput.ReadToEnd();
而且它似乎不起作用——输出没有返回。但是,所有这些场景都可以正常工作(产生所需的输出):
p.StartInfo.FileName=“Powershell.exe”;p、 StartInfo.Arguments=“获取服务”代码>-工作正常
- 从命令行调用PS脚本也可以正常工作(从CMD调用):
我知道有人建议在System.Management.Automation命名空间中使用PowerShell类。我感兴趣的是——为什么?有没有可能在没有这个类的情况下使用PS?也许我的代码根本就错了?是的,这当然是可能的。 在您调用的脚本中,尝试将
替换为写入主机
。写入输出
不写入标准流,而是写入控制台主机。如果您没有运行控制台主机(cmd/powershell控制台),则输出将消失。通常,最好避免同时使用写入主机
。写主机
大多数人建议使用
方法的原因是,它简化了您可能希望与powershell一起使用的许多交互,而不是试图解析powershell.exe的返回,但是,直接调用exe是有充分理由的,例如,如果您使用.net core,当前不完全支持System.Management.Automation
您应该从System.Management.Automation
NS调用PS脚本,因为这样您就可以在类型安全的环境中处理结果和异常 编辑此外,您可以使用异步执行,也可以在远程服务器上执行PS脚本。通常,使用该库的可能性要大得多 你可以看看我下面的例子System.Management.Automation
string script = ""; // PS script content List<ScriptParameter> ExecParamList; // parameters var result = new ExecPSResult(); // Class with list of outputs and errors using (var powerShellInstance = PowerShell.Create()) { powerShellInstance.AddScript(script); foreach (var execParamModel in ExecParamList) { powerShellInstance.AddParameter(execParamModel.ParamName, execParamModel.ParamValue ?? "$null"); } var psOutput = powerShellInstance.Invoke(); result.Errors = powerShellInstance.Streams.Error.Select(e => ExecException.MakeFromException(e.Exception) // just make models for exeptions ).ToList(); result.OutputItems = psOutput.Where( outputItem => outputItem != null && outputItem.TypeNames[0] != "System.ServiceProcess.ServiceController") .Select(e => new ExecOutput { ObjectTypeFullName = e.BaseObject.GetType().FullName, ObjectValue = e.BaseObject //This is typeof(Object) }).ToList(); } return result;
在p.Start之后,您正在从读取到结束,但在您从读取到结束时,它可能还没有完成powershell的启动。似乎此用户使用外部BAT文件启动PS-@thepip3r-路径正确打印到控制台,这是结果:string script=”“;//PS脚本内容 List ExecParamList;//参数 var result=new ExecPSResult();//使用输出和错误列表初始化 使用(var powerShellInstance=PowerShell.Create()) { powerShellInstance.AddScript(脚本); foreach(ExecParamList中的var execParamModel) { powerShellInstance.AddParameter(execParamModel.ParamName, execParamModel.ParamValue???“$null”); } var psOutput=powerShellInstance.Invoke(); 结果。错误= powerShellInstance.Streams.Error.Select(e=> MakeFromException(e.Exception)//只为例外创建模型 ).ToList(); 结果输出项= 输出,在哪里( 输出项=> outputItem!=null&& outputItem.TypeNames[0]!=“System.ServiceProcess.ServiceController”) .选择(e=>new ExecOutput { ObjectTypeFullName=e.BaseObject.GetType().FullName, ObjectValue=e.BaseObject//这是typeof(Object) }).ToList(); } 返回结果;
不只是为了使用API(Powershell.exe-文件C:\Users\bernam\Downloads\test\u scripts\test\u scripts\Mindaugas\u scripts\test.ps1
)直接在C#中而不是启动System.Management.Automation
进程?@MindaugasBernatavičius对您的总体问题的简单回答是,没有理由不使用额外的DLL就无法独立启动进程。DLL将允许您在粒度级别与PowerShell进程交互。如果你刚开始一个进程,你基本上有一个返回值的黑盒。例如,使用DLL,您可以通过C#代码在管道中将许多命令排队。这些命令将通过逻辑插入到您的C#代码中,因此它们在每个用例中可能完全不同。Write-Host也可以工作,但非常感谢您的建议。我将阅读我使用的每个cmd'let的输出。问题的原因一直在STDERR中,但我没有看到它,因为我没有打印出来:)。。。我没有指定powershell.exe
,它给了我禁用执行的错误:)“-executionpolicy bypass”
1..10 | % { Write-Host $_ ; sleep -m 500}
string script = ""; // PS script content List<ScriptParameter> ExecParamList; // parameters var result = new ExecPSResult(); // Class with list of outputs and errors using (var powerShellInstance = PowerShell.Create()) { powerShellInstance.AddScript(script); foreach (var execParamModel in ExecParamList) { powerShellInstance.AddParameter(execParamModel.ParamName, execParamModel.ParamValue ?? "$null"); } var psOutput = powerShellInstance.Invoke(); result.Errors = powerShellInstance.Streams.Error.Select(e => ExecException.MakeFromException(e.Exception) // just make models for exeptions ).ToList(); result.OutputItems = psOutput.Where( outputItem => outputItem != null && outputItem.TypeNames[0] != "System.ServiceProcess.ServiceController") .Select(e => new ExecOutput { ObjectTypeFullName = e.BaseObject.GetType().FullName, ObjectValue = e.BaseObject //This is typeof(Object) }).ToList(); } return result;