PowerShell stdout trouble

本文关键字:trouble stdout PowerShell | 更新日期: 2023-09-27 18:27:49

传统程序"LegacyBuilder"运行"batch.cmd"文件,然后将其输出重定向到一个文件,如下所示。

ProcessStartInfo processStartInfo = new ProcessStartInfo("C:''batch.cmd");
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
using (Process process = Process.Start(processStartInfo))
{
    using (StreamWriter logWriter = new StreamWriter("C:''log.txt"))
    {              
        while ((logLine = process.StandardOutput.ReadLine()) != null)
        {
            logWriter.WriteLine(logLine);
        }
    }
}

batch.cmd包含以下行

C:'SomeApp.exe "arg1" "arg2" "arg3"

SomeApp.exe正在使用来自其他程序集的以下方法。

SomeAssembly.SomeClass.GenerateOutput()

此GenerateOutput方法为第三方控制台程序创建一个进程。在遇到缓冲区死锁的问题后,我发现(从我认为的另一个SO问题中)以下代码从未导致这种死锁,第三方程序的输出被"LegacyBuilder"捕获。

Console.Write("I'm creating the process!");
ProcessStartInfo processStartInfo = new ProcessStartInfo("C:''3rdPartyConsoleExe.exe");
processStartInfo.RedirectStandardOutput = true;
processStartInfo.RedirectStandardError = true;
processStartInfo.UseShellExecute = false;
using (Process process = new Process())
{
    process.StartInfo = processStartInfo;
    using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
    using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
    {    
       process.OutputDataReceived += (sender, e) =>
       {
         if (e.Data == null) outputWaitHandle.Set();
         else output.AppendLine(e.Data);
       };
       process.ErrorDataReceived += (sender, e) =>
       {
         if (e.Data == null) errorWaitHandle.Set();
         else error.AppendLine(e.Data);
       };
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    if (process.WaitForExit(60000) && outputWaitHandle.WaitOne(60000) && errorWaitHandle.WaitOne(60000))
    {
        Console.WriteLine(output.ToString());
        Console.WriteLine(error.ToString());
        if (process.ExitCode > 0)
            Console.WriteLine("PROCESS COMPLETED ExitCode=" + process.ExitCode.ToString());
    }
        else
            Console.WriteLine("PROCESS TIMED OUT");
    }
}

请注意Console.Write("我正在创建流程!");

到目前为止,一切都很好,所有输出都被"LegacyBuilder"捕获

现在,batch.cmd通过调用powershell脚本进行了更新。

C:'Windows'SysWOW64'WindowsPowerShell'v1.0'PowerShell.exe -File "C:'powershellscript.ps1"

powershell脚本基本上加载SomeAssembly,创建SomeObject,然后调用GenerateOutput方法。就像这样。

Add-Type -Path "C:'SomeAssembly.dll";
$someCls = New-Object SomeAssembly.SomeClass()
$someCls.GenerateOutput();

问题是:"LegacyBuilder"正在捕获文本"我正在创建流程!",因此这将被发送到stdout。

但是GenerateOutput()方法的预期输出没有生成任何内容,在尝试了几次调用后,它再次陷入僵局。甚至没有调用"进程超时"。

这很奇怪。

batch.cmd调用"SomeApp.exe",后者调用SomeAssembly.SomeClass.GenerateOutput()。第三方程序的输出出现在文件中,batch.cmd成功继续。

batch.cmd调用powershell,后者加载一个脚本,创建SomeAssembly.SomeClass对象,然后调用GenerateOutput()方法。输出不存在,只有来自直接控制台的输出。写入调用是。。。在几次尝试之后,它会死锁,batch.cmd永远不会继续。

有什么帮助吗?我希望存在类似"StopBufferDeadlocksInPowershell-includeSetupLegacyNestedProcessCalls"的内容。。。

编辑1

我希望避免在"LegacyBuilder"中进行任何更改,因为其中的代码非常非常复杂(最上面的代码示例只是简化),虽然我希望完全重写它,但这将非常耗时。

PowerShell stdout trouble

在经历了几天的头痛之后,不知怎么的,这让它发挥了作用。

$someCls.GenerateOutput() | Out-Host;

缓冲区不再死锁。