Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.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
PowerShell:为什么我可以';有时会重定向外部方法的stdout和stderr吗?_Powershell_Redirect_Stdout_Stderr - Fatal编程技术网

PowerShell:为什么我可以';有时会重定向外部方法的stdout和stderr吗?

PowerShell:为什么我可以';有时会重定向外部方法的stdout和stderr吗?,powershell,redirect,stdout,stderr,Powershell,Redirect,Stdout,Stderr,我在重定向非.NET程序集方法调用的输出时遇到问题: 在下面的代码中,您可以看到一个成功的.NET类System.NET.Dns重定向和两个失败的重定向 一个是内联C#类型,另一个是VS compiled.dll,它只包含与$cs#u代码块相同的内容 到目前为止,我唯一的解决方法是使用[Console]::SetOut和[Console]::SetError捕捉它们的输出 但是为什么它们会失败?我如何重定向/捕获这些流 输出 tl;博士: 如果要从通过[Console]API生成输出的进程内代

我在重定向非.NET程序集方法调用的输出时遇到问题:

在下面的代码中,您可以看到一个成功的.NET类System.NET.Dns重定向和两个失败的重定向

一个是内联C#类型,另一个是VS compiled.dll,它只包含与$cs#u代码块相同的内容

到目前为止,我唯一的解决方法是使用[Console]::SetOut和[Console]::SetError捕捉它们的输出

但是为什么它们会失败?我如何重定向/捕获这些流 输出


tl;博士

  • 如果要从通过
    [Console]
    API生成输出的进程内代码中捕获输出,则必须通过您在问题中提到的
    [Console]::SetOut()
    [Console]::SetError()
    使用显式重定向

  • 请参见下文,了解为什么需要这样做


PowerShell仅允许捕获/重定向标准的
stdout
stderr
外部(控制台)程序流,对于基于.NET的程序,在这些程序中,
console.WriteLine()
console.Out.WriteLine()
写入
stdout
,和
Console.Error.WriteLine()
写入
stderr

在控制台窗口中运行时,默认情况下,PowerShell会将外部程序的stdout和stderr流传递到控制台(屏幕);相反,ISE将stderr输出发送到PowerShell的错误流[1]

1>
重定向外部程序的标准输出(指向文件或
$null
以抑制它),
2>
重定向标准输出[2]。
此外,将外部程序的输出分配给变量会捕获其标准输出,通过管道发送外部程序的输出会将其标准输出重定向到PowerShell的成功输出流


相比之下,您使用的是进程中的
[Console]
类型的输出方法,在这种情况下不可能捕获,因为这种方法只调用输出到PowerShell本身运行的同一控制台,而PowerShell不知道它。[3]

您可以删除中间人以验证此行为:

PS> [Console]::WriteLine('hi')  *> $null # Try to suppress ALL output streams.
hi  # !! Still prints to the console - PowerShell streams were bypassed.
(暂时)重定向
[Console]
进程中输出的唯一方法是显式调用和,如问题中所述

&{[System.Net.Dns]::Resolve('bla')}2>$NULL
中的
2>$NULL
之所以有效,是因为该方法引发异常,PowerShell将异常输出到其错误流(流号
2
),其输出
2>$NULL
有效抑制。
注意,由于抛出异常,
2>$NULL
仅在方法调用包含在
&{…}
中时有效;否则,异常也会终止重定向本身。
然而,对于进程中的
[Console]
行为(不涉及任何异常),是否涉及
&{…}
没有区别


因此,为了使自定义C#方法与PowerShell的流集成(除了在C#代码中直接使用PowerShell API),请执行以下操作:

  • 使用
    return
    获取应进入PowerShell成功流的内容
    (流编号
    1

  • 为应转至PowerShell错误流的内容引发异常(流编号
    2
    ),但请注意,默认情况下,未经处理的异常将作为一个整体中止封闭语句


或者,将您的C#代码编译为外部程序,例如,
godemo.exe

# With an external executable, redirections work as expected.
godemo.exe 1> $null 2> $null 

[1] ISE中的这种分歧行为是有问题的;这一点在本文中进行了讨论

[2] 如果
$ErrorActionPreference='Stop'
恰好生效,则任何
2>
重定向都会意外导致脚本终止错误;中讨论了这种有问题的行为


[3] 这些方法写入当前控制台的
stdout
stderr
流,在没有外部重定向的情况下,这些流会打印到屏幕上。

PowerShell引擎对
console.Out
console.Error
一无所知,这与当前目录的情况非常相似。存在powershell引擎的当前目录/路径,可以使用set-Location(别名cd)进行设置,但也存在powershell进程的当前目录,可通过[Environment]::CurrentDirectory.访问。涉及文件的NET调用使用进程的当前目录,而不是powershell引擎的当前目录。@mikez:不,这里的问题是进程内与外部程序,而不是powershell与..NET:使用
[Console]
API进程内只是打印到控制台,同一进程中没有其他代码—无论是C#还是PowerShell—看到该输出,除非通过
.SetOut()
/和
.SetError()
方法应用了显式重定向。我只使用&{}包装调用,因为它被用作解决类似问题的解决方法。@andiDo:white
&{…}
仅在涉及异常时才起作用(
System.Net.Dns]::Resolve('bla')
,在您的示例中);对于
[控制台]::WriteLine()
。。。没关系。请查看我的更新。我不知道进程中捕获的异常。所以.exe中的Console.WriteLine()会写入stdout,但在.dll中使用时不会,对吗?log4net需要它,它使用控制台调用来获取内部调试消息,我想捕获它们。然后我只需要使用SetOut()和SetError()来捕获库。很高兴知道。非常好的回答,顺便说一句。谢谢,mklement0@mklement0考虑到这一点,马
# With an external executable, redirections work as expected.
godemo.exe 1> $null 2> $null