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"中进行任何更改,因为其中的代码非常非常复杂(最上面的代码示例只是简化),虽然我希望完全重写它,但这将非常耗时。
在经历了几天的头痛之后,不知怎么的,这让它发挥了作用。
$someCls.GenerateOutput() | Out-Host;
缓冲区不再死锁。