октябрь 2016

Том 31 Номер 10

Главное в .NET - Windows PowerShell продолжает меняться в лучшую сторону

Марк Михейлис | октябрь 2016

Марк МихейлисВ качестве отхода от фокуса на .NET Core сегодня я намерен уделить основное внимание ряду новых средств, значительно повышающих мощь Windows PowerShell. Для меня самые важные усовершенствования лежат в области кросс-платформенной поддержки. Да, представьте, PowerShell теперь работает в Linux. Более того, его исходный код открыт и выложен на GitHub (github.com/PowerShell/PowerShell), чтобы сообщество в целом могло приступить к расширению ее возможностей. Потрясающе!

Но самые недавние объявления не отражают всю полноту новшеств. PowerShell 5.0 была выпущена еще в феврале и включает новую и улучшенную поддержку объявлений классов и перечислений, обнаружения модулей и скриптов, управления упаковкой и установкой, доступа к конечным точкам OData, улучшенные средства протоколирования и др. В этой статье я дам обзор каждого из этих средств и предоставлю примеры.

PowerShell становится кросс-платформенной

Для начала взгляните на следующий командный скрипт, который устанавливает PowerShell в Ubuntu 14.04 с Windows PowerShell Host, и экранный снимок сеанса выполнения из Windows Bash на рис. 1. (Для тех, кто не знаком с Bash, выполняющим Ubuntu в Windows 10 Anniversary Update, см. врезку «Установка Bash в Windows 10».)

wget -O powershell.deb https://github.com/PowerShell/
  PowerShell/releases/download/v6.0.0-alpha.9/
  powershell_6.0.0-alpha.9-1ubuntu1.14.04.1_amd64.deb
sudo apt-get install libunwind8 libicu52
sudo dpkg -i powershell.deb
powershell

Установка и запуск Windows PowerShell в Ubuntu 14.04 из Bash в Windows
Рис. 1. Установка и запуск Windows PowerShell в Ubuntu 14.04 из Bash в Windows

Заметьте, что командный скрипт предназначен специально для Ubuntu 14.04. Для других платформ URL пакета deb и версии обязательных компонентов будут отличаться. Инструкции для конкретной платформы см. по ссылке bit.ly/2bjAJ3H.

Много лет назад Джеффри Сноувер (Jeffrey Snover) опубликовал твит о том, что через некоторое время PowerShell мог бы появиться в Linux, но этот процесс занял гораздо дольше, и за весь период было так мало сообщений о прогрессе, что даже сегодня, когда я использую PowerShell, я не перестаю удивляться. Я запускаю Bash поверх Ubuntu, выполняемой в Windows (без применения какой-либо технологии виртуализации), и (предполагая, что я не хочу устанавливать PowerShell прямо в тот же экземпляр Bash) использую SSH для подключения к удаленному сеансу Bash, где можно установить PowerShell и передавать .NET-объекты между командами внутри оболочки Bash.

Если бы еще несколько лет назад я предположил, что такое будет возможным, сомневаюсь, что кто-нибудь поверил бы мне.

Установка Bash в Windows 10

Начиная с Windows 10 Anniversary Edition, в Windows можно устанавливать Bash как «родную» оболочку, используя следующую команду Windows PowerShell:

Get-WindowsOptionalFeature -Online -FeatureName *linux* | Enable-WindowsOptionalFeature -NoRestart -all –online

Но заметьте, что этот функционал пока находится в стадии бета-версии и поэтому включается только в режиме разработчика (используйте Get-Help WindowsDeveloper, чтобы узнать, как исследовать режим разработчика).

К сожалению, этот функционал требует перезагрузки, но я включаю параметр –NoRestart, чтобы включение этого функционала не вызывало немедленной перезагрузки.

Хотя это здорово, что можно писать свои скрипты и библиотеки, скорее всего кто-то из сообщества уже сделал подобное, и вы сможете использовать это и улучшить. Однако до появления PowerShell Gallery (PowerShellGallery.com) приходилось прочесывать Интернет в поисках скриптов и модулей, которые могли быть полезны, — будь то наработки от сообщества или официальные релизы для PowerShell вроде Pscx или модуля Posh-Git. Одно из недавних расширений PowerShell (часть PowerShell 5.0), от которого я стал полностью зависимым, — поддержка нового репозитария специально для PowerShell Gallery. Вообразите, например, что вы писали какое-то время скрипт PowerShell и в процессе этого осознали, что вы должны обходить множество подводных камней, — о, если б только был какой-то способ анализа вашего кода и поиска в нем проблемных мест. Так вот теперь вы можете перейти в PowerShell Gallery и поискать в ней модуль analyze для установки. Или, что еще лучше (поскольку у вас наверняка уже открыто окно PowerShell), использовать команду Find-Module модуля PowerShellGet (включенного в PowerShell 5.0):

Find-Module *Analyze* | Select-Object Name,Description

Вывод этой команды приведен на рис. 2.

Вывод команды Find-Module
Рис. 2. Вывод команды Find-Module

Заметьте: если у вас не установлена достаточно современная версия NuGet, использование модуля PowerShellGet вызовет обновление NuGet.

Предполагая, что вы нашли нужный модуль, его содержимое можно просмотреть командой Save-Module. Для установки модуля используйте команду Install-Module (в данном случае — Install-Module PSScriptAnalyzer). Это приведет к скачиванию и установке модуля за вас, сделав доступными все функции, включенные в модуль. После установки модуля PSScriptAnalyzer можно вызвать Invoke-ScriptAnalyzer $profile для сканирования вашего профиля и выявления мест, которые анализатор считает неоптимальными. (Заметьте, что больше не надо импортировать модуль для доступа к нему. Функции модуля автоматически индексируются так, чтобы при вызове функции модуля этот модуль автоматически импортировался и был доступен по требованию.)

PowerShell Gallery конфигурируется как репозитарий по умолчанию:

>Get-PSRepository

Name       InstallationPolicy  SourceLocation
----       ------------------  --------------
PSGallery  Untrusted           https://www.powershellgallery.
                               com/api/v2/

В итоге Find-Module работает без проблем. Однако Install-Module будет выводить вам предупреждение о не доверяемом репозитарии. Чтобы избежать этого в предположении, что вы действительно доверяете этому репозитарию, следует задать его как доверяемое командой:

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

Apt-Get для Windows с управлением пакетами PowerShell

Те, кто поработал какое-то время IT-специалистом в мире Linux, несомненно, примут apt-get как должное — скорее всего со скриптами установки, которые загружают среду в момент запуска нового экземпляра Linux. Ну а для тех, у кого такого опыта нет, apt-get является вариантом скачивания и установки программ/пакетов и любых зависимостей прямо из Интернета через командную строку. На рис. 1 показан тривиальный пример такой установки, когда с помощью apt-get устанавливается libunwind8 libicu52, от которой зависит PowerShell (в Ubuntu 14.04). В случае PowerShell 5.0 та же функциональность имеется в Windows (даже не уверен: кричать «Ух ты!» или раздраженно вздохнуть «Наконец-то!» — возможно, и то, и другое).

Для меня самые важные усовершенствования лежат в области кросс-платформенной поддержки. Да, представьте, PowerShell теперь работает в Linux.

PowerShell 5.0 поддерживает не только репозитарии вроде PowerShell Gallery для модулей PowerShell, но и управляющие программы в Windows, называемыми пакетами (packages). Один из таких диспетчеров пакетов — Chocolatey (chocolatey.org), и вы можете добавить его как репозитарий пакетов следующей командой:

Get-PackageProvider -Name chocolatey

Это позволяет использовать PowerShell для поиска пакетов, которые были развернуты в Chocolatey. Например, если вы хотите установить Visual Studio Code, вам нужно лишь ввести такие команды:

Find-Package V*S*Code | Install-Package

Как видите, поддерживаются символы подстановки.

Другие команды Package, с которыми следует ознакомиться, доступны с помощью команды, приведенной ниже. Результаты ее выполнения показаны на рис. 3.

Get-Help "-package" | Select-Object Name,Synopsis

Доступные команды Package в Windows PowerShell
Рис. 3. Доступные команды Package в Windows PowerShell

Как видите, можно как получить, так и удалить пакет. Get-Package перечисляет все программы (и другие элементы), доступные из Programs and Features в Control Panel. Поэтому, если вы хотите удалить, например, Notepad2, вы могли бы использовать команду:

Get-Package Notepad2* | Uninstall-Package

Это колоссальным образом упрощает автоматизацию настройки компьютера с Windows. Я являюсь приверженцем Chocolatey вот уже несколько лет, и сейчас появилась возможность интегрировать поддержку Chocolatey непосредственно в Windows. Тем самым в конечном счете в Windows появится примерно такое же управление пакетами, как и достигаемое с помощью Apt-Get в Linux.

Репозитарий Chocolatey доступен через команды *–package* в PowerShell, но Chocolatey также можно установить напрямую. Хотя это не обязательно, установка Chocolatey напрямую иногда дает более надежный набор функционала для управления пакетами. К счастью, установка Chocolatey заключается в простом вызове команды Install-Package Chocolatey. Однако (и это пример расхождения в поведении Chocolatey, установленного напрямую и через *–Package) каталог установки по умолчанию будет зависеть от того, какой механизм установки используется. Подробнее о наборе инструментов Chocolatey, включая инструкции по установке в вашей среде, см. на chocolatey.org/install.

Работа с OData с помощью Export-ODataEndpointProxy

Другая функция PowerShell 5.0, о которой стоит упомянуть, — возможность генерации набора методов, которые обращаются к источнику данных OData, например к Visual Studio Team Services (VSTS). На рис. 4 демонстрируется выполнение Export-ODataEndpointProxy применительно к OData-сервису, в данном случае — к общедоступному примеру OData-сервиса Northwind.

Генерация и вызов OData-прокси
Рис. 4. Генерация и вызов OData-прокси

Если вы просмотрите команды сгенерированного модуля, то заметите, что для каждой сущности (Advertisement, Category, Person и т. д.) наряду с соответствующими действиями (Get, New, Remove, Set) генерируются отдельные команды.

Обратите внимание на командную строку на рис. 4: в ней используется параметр –AllowUnsecureConnection. Это необходимо, так как OData-сервис, используемый в этом примере, не требует аутентификации или шифрования.

Преобразование из текста в объекты с помощью ConvertFrom-String

Еще одна новая команда в PowerShell 5.0 — ConvertFrom-String. Она принимает на входе структурированный текст и интерполирует структуру так, чтобы вывести объект на основе разобранного текста. Вы могли бы использовать ее. например, для разбора плоского файла или (где я нахожу ее крайне полезной) для преобразования текстового вывода от исполняемого файла в какой-либо объект.

Рассмотрим, к примеру, программу handle.exe от SysInternal, (ее можно установить командой Install-Package Handle, используя управление пакетами, как обсуждалось в предыдущем разделе). Как и следовало ожидать от утилиты командной строки, они записывает текст в stdout — в данном случае это список открытых описателей (handles), связанных с указанным именем. Но в PowerShell вы привыкли работать с объектами. И чтобы преобразовать текстовый вывод в объект, используйте функцию ConvertFrom-String, как показано на рис. 5.

Использование ConvertFrom-String для разбора stdout в объект
Рис. 5. Использование ConvertFrom-String для разбора stdout в объект

На рис. 5 сначала отображается исходный вывод от утилиты handle.exe. Затем демонстрируется работа ConvertFrom-String без параметров. В итоге утилита ConvertFrom-String просто разбивает текст в каждой строке по пробелам.

В третьем примере демонстрируется вариант с регулярным выражением с целью тонкой настройки разбора. Но заметьте, что знакомства с регулярными выражения не требуется. Вместо этого вы можете указать шаблон (возможно, точнее будет сказать — образец) либо файла, либо строки, в которые вы вручную разбираете первые несколько элементов. Затем ConvertFrom-String использует образец разбора содержимого и интерпретирует, как разобрать остальной ввод.

В последнем примере я добавил параметр –PropertyNames, чтобы назначать осмысленные имена для вывода.

В общем, ConvertFrom-String перебрасывает мостик между мирами традиционного вывода текста в stdout и PowerShell, опирающейся на объекты. В данном случае я могу конвейеризовать вывод в Stop-Process –Id, преобразующий значение pid в значение параметра –Id.

Классы и перечисления

И наконец, я дам краткий обзор по поддержке классов и перечислений. В PowerShell 5.0 добавили два новых ключевых слова, соответствующих этим двум структурам, чтобы теперь вы могли объявить класс или перечисление прямо в PowerShell (вместо использования Add-Type и передачи C#-кода или создания экземпляра PSCustom­Object). Синтаксис вполне отвечает вашим ожиданиям, как показано на рис. 6.

Рис. 6. Объявление классов и перечислений в Windows PowerShell

enum CustomProcessType {
  File
  Section
}
class CustomProcess {
  [string]$ProcessName;
  hidden [string]$PIDLabel;
  [int]$PID;
  hidden [string]$TypeLabel;
  [CustomProcessType]$Type;
  [int]$Handle;
  [string]$Path;
  CustomProcess(
    [string]$processName,[string]$pidLabel,[int]$pid,
    [string]$typeLabel,[string]$type,[int]$handle,
      [string]$path) {
    $this.ProcessName = $processName;
    $this.PIDLabel=$pidLabel;
    $this.PID=$pid;
    $this.TypeLabel=$typeLabel;
    $this.Type=$type;
    $this.Handle=$handle;
    $this.Path=$path;
  }
  CustomProcess() {}
  GetProcess() {
    Get-Process -Id $this.PID
  }
  static StopProcess([CustomProcess]$process) {
    Stop-Process -Id $process.PID
  }
}

Обратите внимание, что поддерживаются как свойства, так и методы. Есть и модификаторы объявлений вроде static и hidden. Более того, поддерживается наследование с синтаксисом, очень похожим на таковой в C#:

class Employee : Person {}

Наконец, что тоже демонстрируется на рис. 6, можно объявлять конструкторы. В этом примере я объявляю конструктор по умолчанию (без параметров) и второй конструктор, который принимает все параметры. Конструкторы вызываются через команду New-Object либо с указанием параметра –ArgumentList (где перечисляется массив аргументов конструктора), либо с передачей аргумента HashTable через параметр –Property.

ConvertFrom-String перебрасывает мостик между мирами традиционного вывода текста в stdout и PowerShell, опирающейся на объекты.

Заключение

Мы обсудили далеко не полный список новых возможностей PowerShell 5.0. Другие существенные возможности включают следующее.

  • Интеграция архива (поддержка файлов .zip) командами Compress-Archive и Expand-Archive.
  • Команды Get-Clipboard и Set-Clipboard, также работающие с оператором конвейера.
  • Out-File, Add-Content и Set-Content включают параметр –NoNewline, обеспечивая поддержку содержимого файлов, где нет символов новой строки.
  • Команда New-TemporaryFile работает аналогично [System.IO.Path]::GetTempFileName (но не идентично). Как и его .NET-эквивалент, New-TemporaryFile не удаляет временный файл, поэтому позаботьтесь о сохранении вывода, чтобы можно было удалить временный файл по окончании работы с ним.
  • SymbolicLinks теперь можно управлять непосредственно из командлетов PowerShell New-Item и Remove-Item.
  • PowerShell Integrated Scripting Environment (ISE) теперь поддерживает протоколирование через функции Start/Stop/Search-Transcript, которые ранее давали ошибки при вызове из PowerShell ISE.

Более того, хотя в данный момент в релизе PowerShell с открытым исходным кодом нет поддержки Open SSH, Microsoft намерена ввести эту поддержку, чтобы сделать его одним из вариантов транспорта для удаленного взаимодействия (remoting transport) в PowerShell, а также в Windows Remote Management. Появление этой поддержки ожидается буквально после публикации этой статьи.

Итак, PowerShell по-прежнему становится все лучше и лучше. Если вы еще не освоили ее, не откладывайте это в долгий ящик.


Марк Михейлис (Mark Michaelis) — учредитель IntelliTect, где является главным техническим архитектором и тренером. Почти два десятилетия был Microsoft MVP и региональным директором Microsoft с 2007 года. Работал в нескольких группах рецензирования проектов программного обеспечения Microsoft, в том числе C#, Microsoft Azure, SharePoint и Visual Studio ALM. Выступает на конференциях разработчиков, автор множества книг, последняя из которых — «Essential C# 6.0 (5th Edition)». С ним можно связаться в Twitter (@markmichaelis) или по электронной почте mark@IntelliTect.com.

Выражаю благодарность за рецензирование статьи экспертам IntelliTect Кевину Босту (Kevin Bost), Филу Споукасу (Phil Spokas) и Майклу Стоуксбери (Michael Stokesbary).