Ответ 1
Нет такой автоматической переменной.
Вам нужно сделать:
$output = Get-Something
$output
$anObj = $output
чтобы получить поведение
Я ищу функцию, сопоставимую с переменной "_" переменной интерактивной оболочки Python. В PowerShell я хочу что-то вроде этого:
> Get-Something # this returns an object and display it to the output.
# Now I want to assign that object to some variable
> $anObj = ???
Нет такой автоматической переменной.
Вам нужно сделать:
$output = Get-Something
$output
$anObj = $output
чтобы получить поведение
Последний вариант, требующий большей части работы, но IMO дает вам то, о чем вы просите: создать прокси, который перезапишет Out-Default (который всегда называется неявно в конце конвейера, если вы не выходите из-за чего-то другого).
Джеффри Сновер дал ему презентацию во время одного из PowerShell Deep Dives (я считаю, что это был первый) - вы можете найти сценарии, которые он использовал (в том числе вышеупомянутый по умолчанию), на Блог Дмитрия Сотникова. Вы также можете смотреть видео, чтобы понять всю концепцию.
Я добавил в блог еще один расширенный подход к этой проблеме
https://mnaoumov.wordpress.com/2015/01/11/powershell-auto-variable-lastresult/
Вы также можете распечатать результат команды и захватить выходные объекты с помощью параметра OutVariable, а затем использовать $anObj для отображения содержимого переменной.
Get-Something -OutVariable anObj
Как уже говорилось, для этого нет встроенной поддержки, но вот простое, но неоптимальное пользовательское решение PSv3+:
Замечания:
Правильное, но нетривиальное решение см. В полезном ответе BartekB.
В Github существует запрос на добавление этой функции в будущую версию PowerShell Core (на момент написания этой статьи это PowerShell Core 6.1.0).
Добавьте следующее в ваш файл $PROFILE
:
# Store previous command output in $__
$PSDefaultParameterValues['Out-Default:OutVariable'] = '__'
Как назвать переменную - например, $__
(2 подчеркивания) - зависит от вас, но остерегайтесь коллизий имен, особенно с $_
, автоматической переменной, которая представляет входной объект под рукой в ряде контекстов.
Это будет захватывать привязанный к терминалу вывод самой последней выполненной команды [которая выдал вывод терминала] в переменной $__
в ваших интерактивных сеансах, за исключением команд, которые Format-*
командлет форматирования Format-*
, благодаря возможности PowerShell глобально предустановки параметров по умолчанию - см. Get-Help about_Parameters_Default_Values
.
-OutVariable
- это общий параметр, предназначенный для сбора выходных объектов командлета/расширенной функции в переменную, и приведенное выше определение неявно применяет этот параметр ко всем вызовам Out-Default
, которые, в свою очередь, вызываются за кулисами всякий раз, когда PowerShell выводит что-либо в терминал - однако, обратите внимание на исключение re Format-*
командлетов.
Предостережения:
Как уже говорилось, вывод команд, использующих командлет форматирования - Format-Custom
, Format-Hex
, Format-List
, Format-Table
или Format-Wide
- не будет Format-Wide
.
$PSDefaultParameterValues['Format-*:OutVariable'] = '__'
, но, к сожалению, это будет собирать объекты форматирования (инструкции), а не исходные данные в $__
, что нежелательно. Неудовлетворительный обходной путь состоит в том, чтобы захватить Format-*
в другую переменную, которая не только требует, чтобы вы думали о том, на какую переменную нужно нацеливаться, но вы по-прежнему будете видеть только объекты форматирования, а не данные, и, поскольку Format-*
Командлеты задействованы за кулисами, даже если вы не используете их явно, вывод команд без Format-*
затем захватывается дважды - один раз как данные, в $__
, и снова как объекты форматирования, в другой переменной, Из-за особенностей дизайна $__
всегда будет содержать список массивов (типа [System.Collections.ArrayList]
), даже если предыдущая команда выдает только один объект. В случае сомнений используйте $__[0]
для ссылки на один выходной объект.
Остерегайтесь команд, создающих очень большие выходные наборы, потому что $__
будет собирать их в памяти.
$__
будет захватывать только объекты, выводимые на терминал - так же, как _
делает в Python; команда, которая не выдает выходных данных или $null
/массив $null
оставляет любое предыдущее значение $__
без изменений.
Не совсем. Существует автоматическое значение $_, которое содержит текущий объект в строке.
Конвейер - это обычный способ передать результат от одного командлета к следующему, а командлеты настроены на прием параметров из конвейера или из свойств объектов в конвейере, что делает невозможным использование переменной "последний результат".
Однако в некоторых ситуациях требуется конкретная ссылка на объект "piped", а для них есть автоматическое значение $_.
Вот пример его использования: Использование Командлета Where-Object и здесь список автоматических переменных powershell: Глава 4. Автоматические переменные PowerShell
Скрипты в powershell требуют другого стиля, чем программирование на Python (так же, как Python требует другого стиля, чем С++.)
Powershell построена так, что трубы широко используются, если вы хотите разбить трубопровод на более процедурную поэтапную структуру, вам нужно будет сохранить ваши результаты в именованных переменных, а не автоматических.
Как насчет вызова последней команды с помощью "r" (псевдоним для Invoke-History) и переноса ее в круглые скобки() для ее выполнения в первую очередь?
Да, это повторяет последнюю команду, но в моих случаях использования это, безусловно, самое оптимизированное решение, особенно когда я не понимаю, что мне сначала понадобятся последние команды.
Он также сохраняет целостность структуры объекта.
PS C:\Users\user> Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet Intel(R) Ethernet Connection I217-LM 3 Up XX-XX-XX-XX-XX-XX 100 Mbps
PS C:\Users\user> (r) |where {$_.LinkSpeed -eq "100 Mbps"}
Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet Intel(R) Ethernet Connection I217-LM 3 Up XX-XX-XX-XX-XX-XX 100 Mbps
PS C:\Users\user> (r).MacAddress
Get-NetAdapter -InterfaceIndex 3 | Where {$_.State -match "2"}
XX-XX-XX-XX-XX-XX
Используйте модуль PowerShellCookbook и добавьте вызов Add-ObjectCollector к вашему запуску script
Для моего конкретного случая использования я запускал пакетный файл из PowerShell и хотел напечатать вывод этого пакетного файла в режиме реального времени И сохранить его в переменную. Я смог сделать это, отправив вывод моего оператора вызова в Tee-Object
:
$args = @('-r', '-a');
& "C:\myFile.bat" $args | Tee-Object -Variable output;
$output | Set-Clipboard;
Первая команда устанавливает мои аргументы для командного файла. Вторая команда запускает пакетный файл, используя оператор вызова с моими аргументами, и направляет вывод в команду Tee-Object
, которая печатает вывод в режиме реального времени из оператора вызова, но также сохраняет всю информацию в новую переменную называется выход. Последняя команда просто копирует содержимое $output
в буфер обмена.
Tee-Object
также позволяет сохранять выходные данные в файл (кодировка Unicode), и если мне нужно сохранить в файл и переменную (помимо печати в консоль), я могу объединить несколько вызовов в Tee-Object
вместе в одном конвейере., Смотрите эту ссылку для получения дополнительной информации:
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/tee-object
Подход, который сработал для меня, заключается в обработке выходных данных команды с помощью Select-Object
в качестве сквозного. Например, у меня был консольный EXE файл, который выводил подробный вывод в stderr
и значимый вывод в stdout
, из которого я хотел захватить только последнюю строку.
$UtilityPath = ""
(UpdateUtility.exe $ArgList 2>&1) | % {
If ($_ -Is [System.Management.Automation.ErrorRecord]) {
$_.Exception.Message
}
Else {
$_
$UtilityPath = $_
}
}
То, как этот сценарий вызывался, с выводом в поток вывода Error
PowerShell, считалось серьезной ошибкой, которая плохо сочеталась с тем, как PowerShell принимает вывод stderr
внешних приложений и превращает его в вывод Error
. Такой подход оборачивания вывода позволил мне контролировать, как он проходил, а также захватывать строку stdout
я хотел. Мне кажется, что это был бы довольно гибкий подход, который позволил бы вам перехватывать вывод и делать с ним все, что угодно, когда он проходит. Например:
$CommandOutput = ""
SomeOtherCommand | % {
$CommandOutput += "$_'r'n"
$_
}