2015-10-13 5 views
-1

У меня есть сборка C#, которая обрабатывает XML-файл и в конце выводит результаты на консоль.
, например. Console.WriteLine(_header.ToString());
я могу загрузить эту библиотеку DLL в PowerShell и назвать правильный метод, как это:перенаправление вывода из внешней dll в powershell

[sqlproj_doctor.sqlprojDoctor]::ProcessXML($file) | out-file ./test.xml 

Все хорошо.

Проблема начинается, когда я хочу перенаправить вывод. По какой-то причине stdout пуст. Что мне не хватает? Мне нужно продолжить обработку вывода этой DLL.

Примечание. Если я скомпилирую тот же код, что и исполняемый файл, он правильно заполняет стандартный выходной поток, и я могу перенаправить вывод.

другое примечание: в качестве обходного пути я изменил метод от void на строку и теперь могу управлять возвращаемой строкой.

+0

действительно ли он использовать 'Console.WriteLine', а не что-то еще, чтобы отобразить текст на консоли ? – PetSerAl

+0

Я вставил точную строку кода, которая используется в библиотеке классов ... – Mordechai

+0

[расширьте 'TextWriter' и переопределите' WriteLine (string) ', затем назначьте Console] (http://stackoverflow.com/questions/ 6024172/is-it-possible-to-intercept-console-output) –

ответ

2

Когда вы звоните [Console]::WriteLine('SomeText'), это запись в PowerShell процесс стандартный вывод, а не вывода команд, и поэтому он не может быть перенаправлен внутри того же процесса PowerShell, с помощью стандартных операторов PowerShell, например:

[Console]::WriteLine('SomeText')|Out-File Test.txt 

вы должны порождать новый процесс PowerShell, и перенаправить вывод этого нового процесса:

powershell -Command "[Console]::WriteLine('SomeText')"|Out-File Test.txt 

в случае если какая-то команда использование [Console]::WriteLine писать в консоль, вы можете захватить этот вывод без запуска нового экземпляра PowerShell:

$OldConsoleOut=[Console]::Out 
$StringWriter=New-Object IO.StringWriter 
[Console]::SetOut($StringWriter) 

[Console]::WriteLine('SomeText') # That command will not print on console. 

[Console]::SetOut($OldConsoleOut) 
$Results=$StringWriter.ToString() 
$Results # That variable would contain "SomeText" text. 

Хотя это не поможет, если команда не использует [Console]::WriteLine, но писать на стандартный поток непосредственно:

$OldConsoleOut=[Console]::Out 
$StringWriter=New-Object IO.StringWriter 
[Console]::SetOut($StringWriter) 

$Stdout=[Console]::OpenStandardOutput() 
$Bytes=[Console]::OutputEncoding.GetBytes("SomeText"+[Environment]::NewLine) 
$Stdout.Write($Bytes,0,$Bytes.Length) # That command will print on console. 
$Stdout.Close() 

[Console]::SetOut($OldConsoleOut) 
$Results=$StringWriter.ToString() 
$Results # That variable will be empty. 
+0

интересно. Благодарим вас за подробное объяснение примерами. Я смог захватить вывод в строчной записи. Итак, проблема здесь в том, что основная часть моей программы и stdin моего канала перенаправления находятся в другом контексте? И поэтому перенаправление всех stdout на stringwriter работает, потому что весь вывод сбрасывается там независимо от того, в каком контексте выполнения он произошел? – Mordechai

+0

@MorDeror Когда вы вызываете внешнюю dll, он не создает внешний процесс со своим собственным stdout для захвата. Он работает внутри процесса PowerShell. С точки зрения PowerShell, методы .NET не имеют stdout (у PowerShell есть собственный конвейер, основанный на объектах, и он не пытается распознать запись в консоль), у них есть только возвращаемые значения. '[Console] :: SetOut' трюк работает только внутри процесса, и только если вы каким-то образом используете' [Console] :: Out'. Например, PowerShell сам пишет в консоль true WinAPI, и поэтому не затрагивается '[Console] :: SetOut'. – PetSerAl

Смежные вопросы