Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么不能在C中作为常规进程调用Powershell#_C#_Powershell - Fatal编程技术网

C# 为什么不能在C中作为常规进程调用Powershell#

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 =

想知道Powershell是否需要从C#代码调用一个特殊的库(位于System.Management.Automation NS中)?我有以下代码:

        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控制台),则输出将消失。通常,最好避免同时使用
    写主机

    大多数人建议使用
    System.Management.Automation
    方法的原因是,它简化了您可能希望与powershell一起使用的许多交互,而不是试图解析powershell.exe的返回,但是,直接调用exe是有充分理由的,例如,如果您使用.net core,当前不完全支持
    System.Management.Automation

    您应该从
    System.Management.Automation
    NS调用PS脚本,因为这样您就可以在类型安全的环境中处理结果异常

    编辑此外,您可以使用异步执行,也可以在远程服务器上执行PS脚本。通常,使用该库的可能性要大得多

    你可以看看我下面的例子

    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;
    
    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();
    }
    返回结果;
    
    在p.Start之后,您正在从读取到结束,但在您从读取到结束时,它可能还没有完成powershell的启动。似乎此用户使用外部BAT文件启动PS-@thepip3r-路径正确打印到控制台,这是结果:
    Powershell.exe-文件C:\Users\bernam\Downloads\test\u scripts\test\u scripts\Mindaugas\u scripts\test.ps1
    不只是为了使用API(
    System.Management.Automation
    )直接在C#中而不是启动
    powershell.exe
    进程?@MindaugasBernatavičius对您的总体问题的简单回答是,没有理由不使用额外的DLL就无法独立启动进程。DLL将允许您在粒度级别与PowerShell进程交互。如果你刚开始一个进程,你基本上有一个返回值的黑盒。例如,使用DLL,您可以通过C#代码在管道中将许多命令排队。这些命令将通过逻辑插入到您的C#代码中,因此它们在每个用例中可能完全不同。Write-Host也可以工作,但非常感谢您的建议。我将阅读我使用的每个cmd'let的输出。问题的原因一直在STDERR中,但我没有看到它,因为我没有打印出来:)。。。我没有指定
    “-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;