Я хотел бы запустить внешний процесс и записать его вывод команды в переменную PowerShell. Я в настоящее время использую это:
$params = "/verify $pc /domain:hosp.uhhg.org"
start-process "netdom.exe" $params -WindowStyle Hidden -Wait
Я подтвердил, что команда выполняется, но мне нужно записать вывод в переменную. Это означает, что я не могу использовать -RedirectOutput, потому что это только перенаправляет в файл.
powershell
process
Адам Бертрам
источник
источник
Start-Process
для синхронного выполнения (по определению внешних) консольных приложений - просто вызывайте их напрямую , как в любой оболочке; а именно:netdom /verify $pc /domain:hosp.uhhg.org
. Благодаря этому приложение остается подключенным к стандартным потокам вызывающей консоли, что позволяет фиксировать его вывод простым присваиванием$output = netdom ...
. Большинство ответов, приведенных ниже, неявно воздерживаютсяStart-Process
от прямого исполнения.-Credential
параметрStart-Process
обязательно, но только тогда (и если вы хотите выполнить команду в отдельном окне). И следует помнить о неизбежных ограничениях в этом случае: нет возможности записывать вывод, кроме как - без чередования - текст в файлах , через-RedirectStandardOutput
и-RedirectStandardError
.Ответы:
Ты пробовала:
$OutputVariable = (Shell command) | Out-String
источник
Shell Command
на то, что вы хотите запустить. Это так просто.-i
опцию без указания выходного файла. Перенаправление вывода с использованием,2>&1
как описано в некоторых других ответах, является решением.Примечание: используется команда в вопросе
Start-Process
, которая предотвращает прямой захват результатов целевой программы. Как правило, не используйтеStart-Process
для синхронного выполнения консольных приложений - просто вызывайте их напрямую , как в любой оболочке. Благодаря этому приложение остается подключенным к стандартным потокам вызывающей консоли, что позволяет фиксировать его вывод простым присваиванием$output = netdom ...
, как подробно описано ниже.По сути , захват выходных данных из внешних утилит работает так же, как и для собственных команд PowerShell (может потребоваться повышение квалификации при выполнении внешних инструментов ):
Обратите внимание, что
$cmdOutput
получает массив объектов, если<command>
производит более 1 выходного объекта , что в случае внешней программы означает массив строк, содержащий выходные строки программы .Если вы хотите
$cmdOutput
всегда получать одну - потенциально многострочную - строку , используйте$cmdOutput = <command> | Out-String
Чтобы записать вывод в переменную и вывести на экран :
Или, если
<command>
это командлет или расширенная функция, вы можете использовать общий параметр-OutVariable
/-ov
:Обратите внимание , что с
-OutVariable
, в отличие от других сценариев,$cmdOutput
это всегда коллекция , даже если только один объект выводится. В частности,[System.Collections.ArrayList]
возвращается экземпляр типа массива .Посмотрите эту проблему GitHub для обсуждения этого несоответствия.
Чтобы захватить вывод из нескольких команд , используйте либо подвыражение (
$(...)
), либо вызовите скрипт-блок ({ ... }
) с помощью&
или.
:Следует отметить , что общая потребность в префиксом с
&
(оператор вызова) отдельной команды , чье имя / путь цитируемый - например,$cmdOutput = & 'netdom.exe' ...
- не связана с внешними программами таковом (это в равной степени относится и к скриптов PowerShell), но синтаксис требование : PowerShell анализирует оператор, который начинается со строки в кавычках в режиме выражения по умолчанию, тогда как режим аргумента необходим для вызова команд (командлетов, внешних программ, функций, псевдонимов), что и обеспечивает.&
Ключевое различие между
$(...)
и& { ... }
/. { ... }
заключается в том, что первый собирает все входные данные в памяти, а затем возвращает их целиком, а второй - поток , подходящий для обработки конвейера один за другим.Перенаправления также работают в основном так же (но см. Предостережения ниже):
Тем не менее, для внешних команд более вероятно, что следующее будет работать так, как ожидается:
Особенности, относящиеся к внешним программам:
Внешние программы , поскольку они работают вне системы типов 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
( в качестве бонуса, если выход не учитываются, это приводит к правильно перемежаемому выход даже при печати на консоль):источник
<command>
, вы не должны объединять исполняемый файл и его аргументы в одну строку; с помощью вызова черезcmd /c
вас вы можете сделать это, и это зависит от ситуации, имеет ли это смысл или нет. На какой сценарий вы ссылаетесь, и можете ли вы привести минимальный пример?+
оператором; работает также следующее:cmd /c c:\mycommand.exe $Args '2>&1'
- PowerShell позаботится о передаче элементов$Args
в виде строки, разделенной пробелом, в этом случае, функции, называемой « разбрызгивание» .'2>&1'
часть, и не заключающаяся в том,()
что обычно делают многие сценарии.Если вы также хотите перенаправить вывод ошибок, вы должны сделать:
Или, если в имени программы есть пробелы:
источник
Или попробуйте это. Он захватит вывод в переменную $ scriptOutput:
источник
$scriptOutput = & "netdom.exe" $params
Еще один пример из жизни:
Обратите внимание, что этот пример включает путь (который начинается с переменной среды). Обратите внимание, что кавычки должны окружать путь и EXE-файл, но не параметры!
Примечание: не забывайте
&
символ перед командой, но за пределами кавычек.Вывод ошибки также собирается.
Мне потребовалось некоторое время, чтобы эта комбинация работала, поэтому я подумал, что поделюсь ею.
источник
Я попробовал ответы, но в моем случае я не получил необработанный вывод. Вместо этого он был преобразован в исключение PowerShell.
Необработанный результат, который я получил с:
источник
Я получил следующее на работу:
$ результат дает вам необходимое
источник
Эта вещь работала для меня:
источник
Если все, что вы пытаетесь сделать, это захватить вывод команды, то это будет хорошо работать.
Я использую его для изменения системного времени, так как
[timezoneinfo]::local
всегда выдает ту же информацию, даже после того, как вы внесли изменения в систему. Это единственный способ проверить и зарегистрировать изменения в часовом поясе:Это означает, что мне нужно открыть новый сеанс PowerShell, чтобы перезагрузить системные переменные.
источник