如何从cmd.exe重定向标准输出

如何从cmd.exe重定向标准输出,cmd,io-redirection,Cmd,Io Redirection,事实证明,这很难搜索,因为大多数结果都是关于从cmd.exe内部重定向,而不是cmd.exe本身的输出 我有一个简单的C#示例,显示了重定向进程输出并仅打印输出值的工作测试和非工作测试 void Main() { //直接调用nslookup可以正常工作 ProcessStartInfo joy=新的ProcessStartInfo(“nslookup”,@“google.com 8.8.8.8”); //将nslookup作为命令调用到cmd.exe无法按预期工作 ProcessStartIn

事实证明,这很难搜索,因为大多数结果都是关于从cmd.exe内部重定向,而不是cmd.exe本身的输出

我有一个简单的C#示例,显示了重定向进程输出并仅打印输出值的工作测试和非工作测试

void Main()
{
//直接调用nslookup可以正常工作
ProcessStartInfo joy=新的ProcessStartInfo(“nslookup”,@“google.com 8.8.8.8”);
//将nslookup作为命令调用到cmd.exe无法按预期工作
ProcessStartInfo noJoy=新的ProcessStartInfo(Environment.ExpandEnvironmentVariables(“%COMSPEC%”),@“/C nslookup google.com 8.8.8”);
WriteLine($“***正在运行\“{joy.FileName}{joy.Arguments}\”);
Console.WriteLine();
跑(乐);
Console.WriteLine();
WriteLine($“***正在运行\“{noJoy.FileName}{noJoy.Arguments}\”);
Console.WriteLine();
跑步(诺乔伊);
}
无效运行(ProcessStartInfo startInfo)
{
startInfo.CreateNoWindow=true;
startInfo.UseShellExecute=false;
startInfo.RedirectStandardError=true;
startInfo.RedirectStandardOutput=true;
Process proc=新流程();
proc.StartInfo=StartInfo;
proc.EnableRaisingEvents=true;
过程退出+=接收退出通知;
proc.ErrorDataReceived+=接收标准错误数据;
proc.OutputDataReceived+=接收标准输出数据;
proc.Start();
proc.BeginErrorReadLine();
进程BeginOutputReadLine();
进程WaitForExit();
进程ExitCode.Dump();
}
void ReceiveStandardOutputData(对象发送方,DataReceivedEventArgs e)
{
控制台写入线(如数据);
}
void ReceiveStandardErrorData(对象发送方,DataReceivedEventArgs e)
{
控制台写入线(如数据);
}
无效ReceiveExitNotification(对象发送方,事件参数e)
{
控制台写入线(“退出”);
}
这是我从上面得到的结果

*** Running "nslookup google.com 8.8.8.8"... Non-authoritative answer: Server: dns.google Address: 8.8.8.8 Name: google.com Addresses: 2607:f8b0:4002:c08::8b 2607:f8b0:4002:c08::64 2607:f8b0:4002:c08::65 2607:f8b0:4002:c08::66 172.217.10.206 null null Exited 0 *** Running "C:\windows\system32\cmd.exe /C nslookup google.com 8.8.8.8"... null null Exited 0 ***正在运行“nslookup google.com 8.8.8”。。。 非权威性回答: 服务器:dns.google 地址:8.8.8.8 名称:google.com 地址:2607:f8b0:4002:c08::8b 2607:f8b0:4002:c08::64 2607:f8b0:4002:c08::65 2607:f8b0:4002:c08::66 172.217.10.206 无效的 无效的 退出 0 ***正在运行“C:\windows\system32\cmd.exe/C nslookup google.com 8.8.8”。。。 无效的 无效的 退出 0 示例中nslookup的选择是任意的,我尝试过许多其他方法,包括带有副作用的命令,因此我可以确保它按预期执行

我尝试过同步读取,但没有改变

我没有理由相信它与C#或.NET有关。我可以尝试使用direct CreateProcess()测试来确认

对于上下文,它是一个批处理文件,我实际上希望从中获取输出,这就是为什么需要中间cmd.exe进程


在进一步的上下文中,它实际上是一个MSBuild Exec任务,我正试图从中获取输出,因此我对实际调用的控制有限,但我已在调试器中观察了该任务的运行,并将其缩小到了这个问题。

TLDR;问题中的代码示例在任何普通机器上都可以正常工作

因此,事实证明这是一个权限问题。这是一台公司计算机,我拥有有限的权限,但是他们安装了软件,为特定进程提供管理权限。cmd.exe是这些进程中的一个,因此默认情况下它以管理员的身份启动,因此我无法从非提升进程读取输出流

一些几乎可以解决这个问题的想法:

  • 在cmd.exe提示符下,我可以运行
    set\uu COMPAT\u LAYER=RUNASINVOKER
    然后运行第二个运行不相关的cmd.exe,但这并没有真正的帮助,因为我仍然无法获取该流。设置_COMPAT_LAYER环境变量似乎只影响从cmd.exe启动的进程(而不是从.NET的Process.Start()使用的CreateProcess()启动)

  • RunAs.exe有一个/trustlevel开关,我可以用它运行一个不相关的命令,但是我的进程对象是用于RunAs的,它不处理任何重定向,甚至在子进程的生命周期内保持打开状态,因此仍然没有什么好处


但就我而言,我认为最简单的解决方案是最好的。将cmd.exe复制到另一个目录,并将其添加到路径顶部。这修复了提升问题,甚至可以作为我实际问题的最终解决方案,通过MSBuild任务对调用调用的有限访问来处理事件。

您不应该真正运行
“C:\windows\system32\cmd.exe/C nslookup google.com 8.8.8”
,您应该运行
C:\windows\system32\cmd.exe/C“nslookup google.com 8.8.8”
。也就是说,
cmd.exe
/C
参数应该用双引号括起来。