Примечание: используется команда в вопросе 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
от прямого исполнения.