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>
перенаправляет stderr [2] .
Кроме того, назначение вывода из внешней программы переменной захватывает ее вывод stdout и отправляет внешние программывывод по конвейеру перенаправляет свой вывод stdout в поток вывода успешных результатов PowerShell.
В отличие от этого, вы используете методы вывода типа [Console]
in-process , где невозможен такой захват , потому что такие вызовы методапросто выведите на ту же консоль, на которой работает сам 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]
в процессе - это явный вызов .SetOut()
и .SetError()
, как указано в вопросе.
Причина, по которой 2> $NULL
в &{ [System.Net.Dns]::Resolve('bla') } 2> $NULL
работает , заключается в том, что метод генерирует исключение , которое PowerShell выводит в свой поток ошибок (номер потока 2
), выход которого 2> $NULL
эффективно подавляет.
Обратите внимание, что, поскольку выдается исключение , 2> $NULL
действует только потому, что вызов метода заключен в & { ... }
;в противном случае исключение также прервало бы и само перенаправление.
Однако в отношении внутрипроцессного поведения [Console]
без каких-либо исключений, независимо от того, задействовано & { ... }
или нет, разницы нет.
Следовательно, для того, чтобы ваш пользовательский метод C # интегрировался с потоками PowerShell - если не использовать API-интерфейсы PowerShell непосредственно в коде C # - выполните следующие действия:
use return
для того, что должно идти в поток успеха PowerShell (номер потока 1
)
выдает исключение для того, что должно идти в поток ошибок PowerShell (потокчисло 2
), но обратите внимание, что необработанное исключение по умолчанию прервет вмещающий оператор в целом.
В качестве альтернативы скомпилируйте ваш код C # в внешняя программа , скажем, godemo.exe
:
# With an external executable, redirections work as expected.
godemo.exe 1> $null 2> $null
[1] Такое расходящееся поведение в ISE проблематично;это обсуждается в этой проблеме GitHub .
[2] Если действительно действует $ErrorActionPreference = 'Stop'
, любое перенаправление 2>
неожиданно вызывает завершение скриптаошибка;это проблемное поведение обсуждается в этой проблеме GitHub .
[3] Методы записи в потоки stdout
и stderr
текущей консоли, которые вотсутствие перенаправления external , печать на экран.