Примечание: в команде, о которой идет речь, используется 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>
является командлетом или расширенной функцией, вы можетеse общий параметр
-OutVariable
/ -ov
:
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
Обратите внимание, что при -OutVariable
, в отличие от других сценариев, $cmdOutput
всегда равен a collection , даже если выводится только один объект.В частности, возвращается экземпляр типа массива [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, только когда-либо возвращают строки через их поток успеха (стандартный вывод).
Если выходные данные содержат более 1 строки , PowerShell byпо умолчанию разбивает его на массив строк .Точнее, выходные строки хранятся в массиве типа [System.Object[]]
, элементами которого являются строки ([System.String]
).
Если вы хотите, чтобы вывод был один , потенциально многолинейный строка , труба к Out-String
:
$cmdOutput = <command> | Out-String
Перенаправление stderr на стандартный вывод с помощью 2>&1
, чтобы также захватить его как часть потока успеха, поставляется с предостережениями :
Чтобы 2>&1
объединить stdout и stderr в источнике , let 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
, таких каккак %PATH%
.
Обратите внимание, что поскольку вы объединяете stdout и stderr в источнике с помощью этого подхода, вы не сможетеразличать строки, исходящие от stdout и stderr в PowerShell;если вам нужно это различие, используйте перенаправление 2>&1
в PowerShell - см. ниже.
Использование PowerShell 2>&1
перенаправление, чтобы узнать, какие строки пришли из какого потока :
Stderr вывод фиксируется как записи ошибок ([System.Management.Automation.ErrorRecord]
),не строки, поэтому выходной массив может содержать mix из строк (каждая строка представляет строку вывода) и записей ошибок (каждая запись представляетстрока stderr) .Обратите внимание, что по запросу 2>&1
и строки, и записи об ошибках принимаются через поток вывода PowerShell success ).
В консоли ошибказаписи печатаются в красном , а 1-й по умолчанию создает многострочный дисплей в том же формате, в котором отображалась бы не прекращающаяся ошибка командлета; последующие записи об ошибках также печатаются красным, но выводятся только их ошибки , сообщение , в одной строке .
При выводе на консоль строки обычно приходят сначала в выходной массив, за которыми следуют записи об ошибках (по крайней мере, из пакета stdout / stderr)строки выводят «одновременно»), но, к счастью, когда вы захватываете выходные данные, они правильно чередуются , используя тот же порядок вывода, который вы получите без 2>&1
;другими словами: при выводе на консоль захваченный вывод НЕ отражает порядок, в котором строки stdout и stderr были сгенерированы внешней командой.
Если вы захватите весь вывод в одну строку с Out-String
, PowerShell добавит дополнительные строки ,потому что строковое представление записи об ошибке содержит дополнительную информацию, такую как местоположение (At line:...
) и категория (+ CategoryInfo ...
);Любопытно, что это применимо только к первой записи об ошибке . .
- Чтобы обойти эту проблему, примените метод
.ToString()
к каждому объекту вывода вместо конвейера к Out-String
:
$cmdOutput = <command> 2>&1 | % { $_.ToString() }
;
в PS v3 + вы можете упростить до:
$cmdOutput = <command> 2>&1 | % ToString
(В качестве бонуса, если выходные данные не захватываются, это создает правильно чередующиеся выходные данные даже при печати наconsole.)
Либо фильтрует записи ошибок out и отправляет их в поток ошибок PowerShell с помощью Write-Error
(какбонус, если выходные данные не фиксируются, это приводит к правильному чередующемуся выводу даже при печати на консоль):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}