Подтвердить что ты не робот

PowerShell: есть ли автоматическая переменная для последнего результата выполнения?

Я ищу функцию, сопоставимую с переменной "_" переменной интерактивной оболочки 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 = ???
4b9b3361

Ответ 1

Нет такой автоматической переменной.

Вам нужно сделать:

$output = Get-Something
$output
$anObj = $output

чтобы получить поведение

Ответ 2

Последний вариант, требующий большей части работы, но IMO дает вам то, о чем вы просите: создать прокси, который перезапишет Out-Default (который всегда называется неявно в конце конвейера, если вы не выходите из-за чего-то другого).

Джеффри Сновер дал ему презентацию во время одного из PowerShell Deep Dives (я считаю, что это был первый) - вы можете найти сценарии, которые он использовал (в том числе вышеупомянутый по умолчанию), на Блог Дмитрия Сотникова. Вы также можете смотреть видео, чтобы понять всю концепцию.

Ответ 4

Вы также можете распечатать результат команды и захватить выходные объекты с помощью параметра OutVariable, а затем использовать $anObj для отображения содержимого переменной.

Get-Something -OutVariable anObj

Ответ 5

Как уже говорилось, для этого нет встроенной поддержки, но вот простое, но неоптимальное пользовательское решение PSv3+:

Замечания:


Добавьте следующее в ваш файл $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 оставляет любое предыдущее значение $__ без изменений.

Ответ 6

Не совсем. Существует автоматическое значение $_, которое содержит текущий объект в строке.

Конвейер - это обычный способ передать результат от одного командлета к следующему, а командлеты настроены на прием параметров из конвейера или из свойств объектов в конвейере, что делает невозможным использование переменной "последний результат".

Однако в некоторых ситуациях требуется конкретная ссылка на объект "piped", а для них есть автоматическое значение $_.

Вот пример его использования: Использование Командлета Where-Object и здесь список автоматических переменных powershell: Глава 4. Автоматические переменные PowerShell

Скрипты в powershell требуют другого стиля, чем программирование на Python (так же, как Python требует другого стиля, чем С++.)

Powershell построена так, что трубы широко используются, если вы хотите разбить трубопровод на более процедурную поэтапную структуру, вам нужно будет сохранить ваши результаты в именованных переменных, а не автоматических.

Ответ 7

Как насчет вызова последней команды с помощью "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

Ответ 8

Используйте модуль PowerShellCookbook и добавьте вызов Add-ObjectCollector к вашему запуску script

Ответ 9

Для моего конкретного случая использования я запускал пакетный файл из 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

Ответ 10

Подход, который сработал для меня, заключается в обработке выходных данных команды с помощью 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"
    $_
}