Примечание: используется команда в вопросе Start-Process, которая предотвращает прямой захват результатов целевой программы. Как правило, не используйте Start-Processдля синхронного выполнения консольных приложений - просто вызывайте их напрямую , как в любой оболочке. Благодаря этому приложение остается подключенным к стандартным потокам вызывающей консоли, что позволяет фиксировать его вывод простым присваиванием $output = netdom ..., как подробно описано ниже.
По сути , захват выходных данных из внешних утилит работает так же, как и для собственных команд PowerShell (может потребоваться повышение квалификации при выполнении внешних инструментов ):
$cmdOutput = <command> # captures the command's success stream / stdout
Обратите внимание, что $cmdOutputполучает массив объектов, если <command>производит более 1 выходного объекта , что в случае внешней программы означает массив строк, содержащий выходные строки программы .
Если вы хотите $cmdOutputвсегда получать одну - потенциально многострочную - строку , используйте
$cmdOutput = <command> | Out-String
Чтобы записать вывод в переменную и вывести на экран :
<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed
Или, если <command>это командлет или расширенная функция, вы можете использовать общий параметр
-OutVariable/-ov :
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
Обратите внимание , что с -OutVariable, в отличие от других сценариев, $cmdOutputэто всегда коллекция , даже если только один объект выводится. В частности, [System.Collections.ArrayList]возвращается экземпляр типа массива .
Посмотрите эту проблему GitHub для обсуждения этого несоответствия.
Чтобы захватить вывод из нескольких команд , используйте либо подвыражение ( $(...)), либо вызовите скрипт-блок ( { ... }) с помощью &или .:
$cmdOutput = $(<command>; ...) # subexpression
$cmdOutput = & {<command>; ...} # script block with & - creates child scope for vars.
$cmdOutput = . {<command>; ...} # script block with . - no child scope
Следует отметить , что общая потребность в префиксом с &(оператор вызова) отдельной команды , чье имя / путь цитируемый - например, $cmdOutput = & 'netdom.exe' ...- не связана с внешними программами таковом (это в равной степени относится и к скриптов PowerShell), но синтаксис требование : PowerShell анализирует оператор, который начинается со строки в кавычках в режиме выражения по умолчанию, тогда как режим аргумента необходим для вызова команд (командлетов, внешних программ, функций, псевдонимов), что и обеспечивает.&
Ключевое различие между $(...)и & { ... }/ . { ... }заключается в том, что первый собирает все входные данные в памяти, а затем возвращает их целиком, а второй - поток , подходящий для обработки конвейера один за другим.
Перенаправления также работают в основном так же (но см. Предостережения ниже):
$cmdOutput = <command> 2>&1 # redirect error stream (2) to success stream (1)
Тем не менее, для внешних команд более вероятно, что следующее будет работать так, как ожидается:
$cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below.
Особенности, относящиеся к внешним программам:
Внешние программы , поскольку они работают вне системы типов PowerShell, возвращают только строки через поток успеха (stdout).
Если выходные данные содержат более 1 строки , PowerShell по умолчанию разделяет его на массив строк . Точнее, выходные строки хранятся в массиве типа [System.Object[]], элементами которого являются strings ( [System.String]).
Если вы хотите, чтобы выходные данные представляли собой единственную , потенциально многострочную строку , направьтеOut-String :
$cmdOutput = <command> | Out-String
Перенаправление stderr на stdout с2>&1 целью захвата его как части потока успеха сопровождается оговорками :
Чтобы 2>&1объединить stdout и stderr в источнике , давайте cmd.exeобработаем перенаправление , используя следующие идиомы:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /cвызывает cmd.exeс командой <command>и завершает работу после того, <command>как закончил.
- Обратите внимание на одинарные кавычки
2>&1, которые гарантируют, что перенаправление передается, cmd.exeа не интерпретируется PowerShell.
Обратите внимание, что вовлечение cmd.exeозначает, что его правила экранирования символов и расширения переменных среды вступают в игру по умолчанию в дополнение к собственным требованиям PowerShell; в PS v3 + вы можете использовать специальный параметр --%(так называемый символ остановки разбора ), чтобы отключить интерпретацию оставшихся параметров PowerShell, за исключением cmd.exeссылок на переменные окружения -style, таких как %PATH%.
Обратите внимание, что, так как вы объединяете stdout и stderr в источнике с помощью этого подхода, вы не сможете различить строки, происходящие из stdout и stderr, в PowerShell; если вам нужно это различие, используйте 2>&1перенаправление PowerShell - см. ниже.
Используйте перенаправление PowerShell, 2>&1 чтобы узнать, какие строки пришли из какого потока :
Stderr выход захватывается в качестве записей об ошибках ( [System.Management.Automation.ErrorRecord]), а не строк, так что выходной массив может содержать смесь из строк (каждая строка , представляющая собой стандартный вывод строки) и записи об ошибках (каждая запись , представляющая Stderr линию) . Следует отметить, что в соответствии с просьбой 2>&1, как строки и принимаются через PowerShell в записи об ошибках успеха выходной поток).
В консоли, записи об ошибках печати в красном цвете , и первый один по умолчанию производит многострочный дисплей, в том же формате , что не оконечная ошибка командлета , были бы отображаться; последующие записи об ошибках также печатаются красным, но выводят сообщение об ошибке только в одну строку .
При выводе на консоль , строки , как правило , приходят первые в выходном массиве, а затем записи об ошибках (по крайней мере среди партии стандартного вывода / вывода STDERR линии «в то же время»), но, к счастью, когда вы захватить выход , оно правильно чередуется , используя тот же порядок вывода, что и без него 2>&1; другими словами: при выводе на консоль захваченный вывод НЕ отражает порядок, в котором строки stdout и stderr были сгенерированы внешней командой.
Если вы захватите весь вывод в одну строку с помощьюOut-String , PowerShell добавит дополнительные строки , потому что строковое представление записи об ошибке содержит дополнительную информацию, такую как location ( At line:...) и category ( + CategoryInfo ...); Любопытно, что это относится только к первой записи об ошибке.
- Чтобы обойти эту проблему, применить
.ToString()метод к каждому выходному объекту вместо трубопровода к Out-String:
$cmdOutput = <command> 2>&1 | % { $_.ToString() };
в PS v3 + вы можете упростить:
$cmdOutput = <command> 2>&1 | % ToString
(В качестве бонуса, если выходные данные не фиксируются, это создает правильно чередующиеся выходные данные даже при печати на консоль.)
В качестве альтернативы, фильтровать записи об ошибках Out и отправить их в поток ошибок PowerShell сWrite-Error ( в качестве бонуса, если выход не учитываются, это приводит к правильно перемежаемому выход даже при печати на консоль):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}
Start-Processдля синхронного выполнения (по определению внешних) консольных приложений - просто вызывайте их напрямую , как в любой оболочке; а именно:netdom /verify $pc /domain:hosp.uhhg.org. Благодаря этому приложение остается подключенным к стандартным потокам вызывающей консоли, что позволяет фиксировать его вывод простым присваиванием$output = netdom .... Большинство ответов, приведенных ниже, неявно воздерживаютсяStart-Processот прямого исполнения.