Как вы наверняка знаете, некоторое время назад вышла новая версия командной среды и платформы автоматизации PowerShell Core, а именно 6.1. В ней содержится большое количество исправлений и улучшений. И, поскольку рассмотреть каждое изменение в рамках одной статьи у нас не получится, мы сосредоточимся на наиболее важных и полезных нововведениях.
Совместимость
Начавшееся еще в версии 6.0 движение в сторону обеспечения максимально возможной совместимости PowerShell Core с предыдущей итерацией платформы, Windows PowerShell 5.1, в новой версии продолжилось и привнесло значительную часть недостающей функциональности.
Так, в PowerShell Core 6.0 некоторые встроенные в операционную систему Windows модули не функционировали (они есть как в клиентской, так и в серверной редакции), а корректная работа остальных хотя и предусматривалась, но не гарантировалась. Теперь же в этом отношении мы видим значительный прогресс.
PowerShell
Первое, что следует отметить, это, собственно, улучшения в PowerShell Core. Благодаря внесенным изменениям путь C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules теперь является одним из тех мест, в которые PowerShell Core заглядывает при поиске доступных модулей. Это позволяет задействовать расположенные в модулях команды без предварительного добавления указанного выше пути в переменную среды $Env: PSModulePath (в PowerShell Core эта переменная среды не соответствует одноименной системной переменной) или же импорта модуля с указанием его точного расположения.
Кроме того, по умолчанию PowerShell Core 6.1 импортирует только те из расположенных по данному пути модулей, что явным образом были помечены как совместимые. Для этого используется значение свойства CompatiblePSEditions объекта модуля.
В PowerShell Core 6.1 если вы выполните команду Get-Module для еще не импортированного в сессию модуля (потребуется указать параметр ListAvailable), то среди уже привычных столбцов с описывающими модуль данными обнаружите и PSEdition, используемый для отображения значений уже упомянутого свойства CompatiblePSEditions (рисунок 1).
Рисунок 1. Выполнение команды Get-Module для не импортированного в сессию модуля |
Импортировав модуль в сессию и вызвав команду Get-Module без параметра ListAvailable, вы этот столбец уже не увидите (рисунок 2).
Рисунок 2. Выполнение команды Get-Module без параметра ListAvailable |
Если же вы введете команду Get-Module -ListAvailable без указания имени какого-либо модуля, то в качестве результата получите список всех модулей. Однако здесь есть одна важная особенность. Для каждого из указанных в переменной среды $Env: PSModulePath каталогов, кроме C:\WINDOWS\system32\WindowsPowerShell\v1.0\
Modules, будут выведены все находящиеся в нем модули, вне зависимости от значения свойства CompatiblePSEditions и, соответственно, их заявленной совместимости.
Что же касается пути C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules, то для него будут выведены только те модули, чья совместимость с PowerShell Core 6.1 была указана автором явным образом, то есть добавлением значения Core в поле CompatiblePSEditions манифеста модуля.
Тем не менее вы все же можете получить информацию обо всех расположенных и по этому пути модулях, добавив к команде Get-Module параметр SkipEditionCheck.
Get-Module -ListAvailable -SkipEditionCheck
В то же время у вас не получится напрямую использовать какую-либо команду, находящуюся в расположенном в каталоге C:\WINDOWS\system32\WindowsPower
Shell\v1.0\Modules модуле, не обозначенном как совместимый. Однако, если вы уверены в работоспособности этого модуля или же вас устраивает его неполная совместимость с PowerShell Core, вы можете его импортировать, используя уже знакомый нам параметр SkipEditionCheck, и затем воспользоваться нужной командой.
Import-Module -Name SomeNonCompatibleModule -SkipEditionCheck CompatiblePSEditions
Возможность указать совместимость создаваемого вами модуля с Windows PowerShell (значение Desktop) или с PowerShell Core (значение Core) существует еще с Windows PowerShell версии 5.1. Для этого вам потребуется указать нужное значение — или оба — в качестве аргумента для одноименного параметра — CompatiblePSEditions команды New-ModuleManifest. Например, так:
New-ModuleManifest -Path C:\ModuleName\ ModuleName.psd1-CompatiblePSEditions Core, Desktop
Однако в Windows PowerShell 5.1, равно как и в PowerShell Core 6.0, это свойство носило исключительно информационный характер и никак не влияло на обнаружение или же использование модулей.
В PowerShell Core 6.1, как уже говорилось выше, это все еще справедливо для всех содержащих модули каталогов, за исключением C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules. Получается, что разработчики как бы разделили ответственность за использование модулей между собой и пользователями. За каталог, в котором должны находиться исключительно встроенные в операционную систему модули, отвечают их авторы, а за все остальные расположения — сам пользователь.
Учтите, что, если в манифесте модуля значение CompatiblePSEditions не задано, считается, что этот модуль явным образом совместим только с Windows PowerShell, что равноценно указанию значения Desktop.
Модули
Что же касается второго направления работы над улучшением совместимости, то это адаптация встроенных в операционную систему модулей для работы не только с Windows PowerShell, но и с PowerShell Core. И первые результаты этой работы — часть модулей, входящих в Windows 10 версии 1809 и Windows Server 2019.
Как сообщают разработчики, PowerShell Core поддерживают уже 70% команд и 65% модулей. Однако работа продолжается, и в будущих релизах Windows мы сможем увидеть еще большую степень совместимости.
Если же нужная вам команда все еще не поддерживается, вы можете воспользоваться модулем WindowsCompatibility, который позволяет, находясь в PowerShell Core, выполнять недоступные в этой среде команды путем их запуска в Windows PowerShell.
Установить модуль WindowsCompatibility из PowerShell Gallery можно следующим образом:
Install-Module WindowsCompatibility
Windows Compatibility Pack для .NET Core
Продолжая тему совместимости, рассмотрим Windows Compatibility Pack для .NET Core.
Как известно, PowerShell Core создан на платформе .NET Core (что касается PowerShell Core 6.1, то это .NET Core версии 2.1). Основное отличие .NET Core от .NET Framework — кросс-платформенность, что, собственно, и позволяет PowerShell Core работать как на платформе операционной системы Windows, так и на Linux и macOS. Еще одно важное отличие состоит в том, что .NET Core по сравнению с .NET Framework предоставляет доступ к значительно меньшему числу программных интерфейсов.
В качестве меры, призванной частично сгладить это обстоятельство, был выпущен Windows Compatibility Pack для .NET Core, предоставляющий доступ к тем интерфейсам, что прежде были доступны только в .NET Framework. Для того чтобы воспользоваться этими преимуществами, в PowerShell Core 6.0 требовалось установить модуль PSCoreWindowsCompat.
Теперь же Windows Compatibility Pack является частью PowerShell Core 6.1, что, во-первых, дает возможность воспользоваться многими ранее недоступными программными интерфейсами, а во-вторых, значительно повышает вероятность того, что какой-либо не работавший в версии 6.0 модуль начнет функционировать должным образом без необходимости внесения в него изменений.
Markdown
Еще одно значимое изменение — поддержка формата Markdown.
В PowerShell Core 6.1 появились следующие команды: Get-MarkdownOption, Set-MarkdownOption, ConvertFrom-Markdown, Show-Markdown. Get-MarkdownOption и Set-Markdown
Option отвечают, как можно догадаться, за вывод и изменение настроек отображения файлов в формате Markdown; ConvertFrom-Markdown позволяет преобразовать документ Markdown в формат Html или VT100, а Show-Markdown отображает содержимое документа на экране.
Надо сказать, что в PowerShell Core версии 6.1 поддерживается лишь часть элементов Markdown, однако разработчики сообщали о планах дальнейшей интеграции этого формата в PowerShell Core. Кроме того, говорилось и о возможности перехода в будущем на использование Markdown в качестве формата для файлов справки PowerShell Core. Как известно, сейчас для этих целей используется Xml.
Экспериментальные функции
В PowerShell Core 6.1 появилась возможность включать как в саму платформу, так и в отдельные модули некоторые экспериментальные функции (Experimental Features). Под такими функциями следует понимать некие еще не приведенные к окончательному виду механизмы, которые, с одной стороны, могут быть интересны тем, кто хотел бы иметь возможность ознакомиться с ними в их текущем виде, то есть еще до официального выпуска, и, возможно, повлиять на их дальнейшую разработку. Например, можно оставить отзыв на сайте проекта, что опять же поможет авторам в создании окончательного продукта. С другой стороны, эти функции, не будучи явным образом активированными, никак себя не проявят в работе тех пользователей, которые заинтересованы исключительно в готовом продукте.
На сегодня экспериментальные функции могут проявляться следующим образом: ветвление кода, зависящее от того, был ли активирован определенный экспериментальный элемент; наличие, отсутствие или изменение определенных функций или команд PowerShell, а также наличие, отсутствие или замена параметров и их наборов (Parameter Sets).
Проверить, существует ли в текущей версии PowerShell Core или же в установленных модулях некая экспериментальная функция, можно при помощи команды PowerShell Get-ExperimentalFeature. Будучи вызванной без параметров, она возвращает только уже активированные экспериментальные элементы. Для того чтобы получить информацию обо всех существующих экспериментальных функциях, как активированных, так и нет, потребуется указать параметр ListAvailable, уже знакомый вам по команде PowerShell Get-Module.
Get-ExperimentalFeature -ListAvailable
Кроме того, список активированных экспериментальных механизмов содержит и автоматическая переменная $EnabledExperimentalFeatures.
Для того чтобы проверить, активен ли тот или иной экспериментальный элемент, мы можем воспользоваться командой PowerShell Get-ExperimentalFeature с параметром Name
Get-ExperimentalFeature -Name ModuleName.FeatureName
и статическим методом IsEnabled класса System.Management.Automation.ExperimentalFeature.
[System.Management.Automation. ExperimentalFeature]:: IsEnabled ("ModuleName.FeatureName")
Для того чтобы активировать интересующую вас функцию, потребуется внести изменения в файл настроек powershell.config.json, по умолчанию находящийся в том же каталоге, куда был установлен PowerShell Core.
К примеру, файл с настройками, активирующими экспериментальные механизмы с именами PSSomeFeature и SomeModule.SomeFeature, может выглядеть таким образом, как показано на рисунке 3.
Рисунок 3. Настройки, активирующие экспериментальные механизмы с именами |
Чтобы нужная функция была активирована, вам потребуется перезапустить PowerShell Core.
Так же, как и в случае с поддержкой формата Markdown, текущая реализация механизма экспериментальных функций еще не является окончательной. Предполагается, что их возможности будут расширяться и дополняться. Скажем, сейчас мы не можем определять классы как экспериментальные, а также не можем задавать одни экспериментальные элементы как зависимые или же, наоборот, несовместимые с другими.
Удаленные подключения
В PowerShell Core 6.1 несколько изменилась концепция именования наборов настроек сессий (Session Configuration), известных также как точки подключения (Endpoint) и использующихся для выполнения удаленных подключений и определяющих их параметры и особенности.
Теперь, когда вы вызываете команду PowerShell Enable-PSRemoting из официально объявленной версии, такой как PowerShell Core 6.1.0, создаются два набора настроек: PowerShell.6 и PowerShell.6.1.0.
Первый из них, PowerShell.6, предназначен для использования в тех случаях, когда вам не важна конкретная установленная на компьютере версия PowerShell Core, будь то 6.1.0, 6.1.1 или 6.2.0.
Если же вам требуется подключение к конкретной версии, то в этом случае вы можете воспользоваться второй точкой подключения — PowerShell.6.1.0.
Надо сказать, что предварительные (preview) версии также создают два набора настроек. Например, запуск команды Enable-PSRemoting из PowerShell Core версии 6.1.0-rc.1 (Release Candidate 1) создаст наборы PowerShell.6-preview и PowerShell.6.1.0-rc.1.
Настройки PowerShell.6-preview могут быть использованы для подключения к той предварительной версии, что установлена на компьютере в данный момент. Например, до 6.1.0-rc.1 это могла быть версия 6.1.0-preview.4.
Вторая точка подключения — PowerShell Core 6.1.0-rc.1 — явным образом указывает на версию ‘Release Candidate 1’ (рисунок 4).
Рисунок 4. Подключение к сессии Release Candidate 1 |
В отличие от файлов msi, дистрибутивы в формате zip позволяют вам установить на компьютере несколько версий PowerShell Core — как релизных, так и предварительных, и в этом случае вы можете самостоятельно определять, на какие версии будут указывать общие точки подключения, такие как PowerShell.6 и PowerShell.6-preview.
Какую версию PowerShell Core использует та или иная точка подключения, вы можете узнать при помощи команды, показанной на рисунке 5.
Рисунок 5. Определение версии PowerShell Core |
Для того чтобы изменить точку подключения PowerShell.6-preview таким образом, чтобы вместо версии 6.1.0-rc.1 она использовала, например, 6.1.0-preview.4, нужно сначала удалить эту точку подключения при помощи следующей команды (сделать это можно из любой версии PowerShell Core, а не только из 6.1.0-rc.1):
Unregister-PSSessionConfiguration -Name PowerShell.6-preview
Затем следует зарегистрировать новую точку подключения при помощи команд Enable-PSRemoting или Register-PSSessionConfiguration, на этот раз уже из той версии, которую вы хотите использовать для удаленных подключений, как показано на рисунке 6.
Рисунок 6. Регистрация новой точки подключения |
Параметр Subsystem
Команды PowerShell New-PSSession, Enter-PSSession и Invoke-Command получили новый параметр — Subsystem. Что он нам дает? Как вы помните, при настройке удаленного доступа по протоколу SSH в файле sshd_config нам нужно указать строку следующего формата
Subsystem powershell C:\pwsh\pwsh.exe -sshs -NoLogo -NoProfile
где второй параметр — это имя подсистемы, а за ним следует путь к исполняемому файлу PowerShell Core, который будет использоваться нашим подключением. Завершается эта строка параметрами для файла pwsh.exe.
Однако мы можем задать несколько подсистем под разными именами, указывающих на различные версии PowerShell Core. Например, так, как на рисунке 7.
Рисунок 7. Указание нескольких подсистем под разными именами |
И теперь, задавая нужное нам имя подсистемы в качестве значения параметра Subsystem, мы можем выбирать, к какой версии PowerShell Core хотим подключиться (рисунок 8).
Рисунок 8. Указание версии PowerShell Core, к которой выполняется подключение |
В первом случае мы не использовали параметр Subsystem, поскольку его значением по умолчанию является ‘powershell’.
Появление параметра Subsystem призвано до некоторой степени приблизить, в первую очередь с точки зрения доступных возможностей, метод удаленного подключения с использованием SSH к уже привычному нам подключению посредством протокола WinRM, где мы можем указывать различные точки подключения при помощи параметра ConfigurationName.
Синтаксис подключений SSH
В PowerShell Core 6.0 для того, чтобы при подключении по протоколу SSH с использованием команд New-PSSession, Enter-PSSession и Invoke-Command указать имя пользователя, имя или адрес хоста, а также в случаях отличия от значения по умолчанию и порт, нам приходилось задействовать несколько параметров.
Enter-PSSession -HostName host -UserName user -Port 222
Теперь же вы можете указать эти значения в одном параметре — HostName — в более привычном пользователям ssh виде.
Enter-PSSession -HostName user@host
Или если мы хотим также указать и порт.
Enter-PSSession -HostName user@host:22
Кроме того, этот синтаксис теперь доступен и при использовании параметра SSHConnection команд New-PSSession и Invoke-Command.
New-PSSession -SSHConnection @{HostName = "user@host:22"}
Изменение строки приглашения SSH
Теперь, если вы подключаетесь к удаленной системе при помощи протокола SSH и указываете учетные данные, отличные от используемых вами на локальном компьютере, то строка приглашения, кроме имени удаленной системы, будет содержать и имя пользователя, под учетной записью которого это подключение происходило (рисунок 9).
Рисунок 9. Изменение строки приглашения SSH |
Модуль ThreadJob
В PowerShell Core 6.1 появился новый модуль для работы с заданиями PowerShell — ThreadJob. Мы уже знакомы с заданиями PowerShell, они предназначены для фонового выполнения команд, чья работа может занять некоторое время. Для взаимодействия с ними предназначены команды PowerShell Start-Job, Get-Job, Stop-Job, Wait-Job, Receive-Job, Remove-Job и Debug-Job.
Например, мы можем запустить некое задание при помощи команды, показанной на рисунке 10. Или же мы можем использовать появившийся в PowerShell Core 6.0 синтаксис, как показано на рисунке 11.
Рисунок 10. Пример запуска задания |
Рисунок 11. Пример запуска задания в PowerShell Core 6.0 |
Однако особенность этих методов состоит в том, что для каждого задания запускается отдельный процесс PowerShell, вследствие чего увеличивается как время выполнения каждого отдельного задания, так и нагрузка на систему в целом.
Что же касается новой входящей в модуль ThreadJob команды Start-ThreadJob, то она запускает каждое задание в отдельном потоке (thread) в рамках существующего процесса, что значительно повышает быстродействие.
Start-ThreadJob -ScriptBlock {Get-Process}
Определенный минус, однако, заключается в том, что этот подход предполагает несколько меньшую изоляцию каждого задания по сравнению с существующим способом, поскольку в этом случае, если некоторое задание приведет к аварийному завершению процесса, выполнение остальных заданий также прервется.
Если мы присмотримся к модулю ThreadJob, то увидим, что состоит он всего лишь из одной команды (рисунок 12). В связи с этим возникает закономерный вопрос — как же нам работать с созданным заданием?
Рисунок 12. Модуль ThreadJob |
Замечательная особенность команды Start-ThreadJob состоит в том, что для дальнейшей работы с запущенными заданиями используются уже существующие команды, такие как Get-Job, Receive-Job и Remove-Job, как показано на рисунке 13.
Рисунок 13. Для дальнейшей работы используются существующие команды |
Как видите, команда Get-Job возвращает как задания, запущенные при помощи Start-Job (те, значение свойства PSJobTypeName которых — BackgroundJob), так и задания, полученные в результате выполнения команды Start-ThreadJob, в свойстве PSJobTypeName которых значится ThreadJob.
Теперь давайте посмотрим, насколько быстрее происходит запуск заданий с использованием команды Start-ThreadJob по сравнению с командой Start-Job. Для этого воспользуемся командой PowerShell Measure-Command (рисунок 14). Как видите, прирост производительности довольно значительный, и это при том, что мы запускали всего лишь одно задание. Если же нам потребуется запустить несколько десятков заданий одновременно, разница будет еще более заметной.
Рисунок 14. Команда PowerShell Measure-Command для проверки Start-ThreadJob |
Кроме того, команда Start-ThreadJob обладает еще несколькими новыми возможностями. Так, команда позволяет указать количество одновременно выполняемых заданий. Проверить это мы можем при помощи параметра ThrottleLimit. Особенность его использования в том, что он задает предел одновременно выполняющихся заданий для текущей сессии PowerShell. Таким образом, если мы выполним набор команд, как на рисунке 15, это приведет к тому, что одновременно будут выполняться только два задания, несмотря на то что вторая и третья команды параметр ThrottleLimit не использовали. И только после того, как одно из них будет завершено, начнется выполнение третьего.
Рисунок 15. Указание количества одновременно выполняемых заданий |
Все запущенные впоследствии в текущем сеансе задания будут выполняться в соответствии с установленным ранее лимитом до тех пор, пока мы его не переопределим при помощи указанного выше параметра.
Еще одна особенность команды Start-ThreadJob состоит в том, что запущенные ею задания в качестве результата возвращают, что называется, живые объекты. Например, если мы получим объект службы — пусть это будет BITS — при помощи команды Start-Job, а затем попробуем ее остановить, используя метод Stop, то получим сообщение об отсутствии у полученного объекта данного метода (рисунок 16).
Рисунок 16. Остановка службы BITS при помощи команды Start-Job |
Однако если то же самое мы сделаем, применив для запуска задания команду Start-ThreadJob, то служба BITS будет остановлена, как показано на рисунке 17.
Рисунок 17. Остановка службы BITS при помощи команды Start-ThreadJob |
Изменения платформы
Раньше, как вы помните, каждая версия PowerShell Core устанавливалась в свою папку. Например, для PowerShell Core 6.0.4 это была папка $Env: ProgramFiles\PowerShell\6.0.4. Начиная с версии 6.1 папка для установки релизных версий PowerShell Core при помощи файлов msi будет следующей: $Env: ProgramFiles\PowerShell\6. Для preview-версий папка будет называться $Env: ProgramFiles\PowerShell\6-preview.
Таким образом, каждая новая версия, будь то окончательная или предварительная, будет устанавливаться поверх предыдущей версии соответствующей ветви. Сделано это для того, чтобы в будущем служба обновления Microsoft Update имела возможность применять исправления или обновлять PowerShell Core, вне зависимости от его текущей версии.
Тем не менее возможность одновременного использования нескольких версий PowerShell Core при помощи файлов установки в формате zip по-прежнему доступна.
Производительность
В PowerShell Core 6.1 заметно возросла производительность как в целом (в том числе благодаря .NET Core версии 2.1), так и в отдельных элементах. Наиболее заметно это проявляется в таких командах PowerShell, как Group-Object, Sort-Object, Import-Csv и ConvertFrom-Json.
К примеру, если мы сравним производительность команды Group-Object в PowerShell Core 6.1 и 6.0.4, то получим результат, приведенный на рисунке 18.
Рисунок 18. Производительность команды Group-Object в PowerShell Core 6.1 и 6.0.4 |
Поддержка AppLocker и Device Guard
PowerShell Core 6.1, как и Windows PowerShell 5.1, теперь поддерживает механизмы определения разрешенных или запрещенных приложений, такие как AppLocker и Device Guard.
PowerShell Direct
PowerShell Direct — это механизм PowerShell и Hyper-V, позволяющий подключиться к виртуальной машине или контейнеру без использования сети. Если раньше, при работе с контейнерами, подключение происходило исключительно к Windows PowerShell, то теперь сначала происходит попытка подключиться к PowerShell Core и только в случае его отсутствия используется Windows PowerShell.
Что же касается подключения к виртуальным машинам, то по умолчанию подключение все так же происходит к Windows PowerShell, однако вы можете это изменить, указав нужную вам точку входа в сессию.
Enter-PSSession -VMName somevm -ConfigurationName PowerShell.6
Причем сделать это вы можете как из PowerShell Core, так и из Windows PowerShell.
Акселераторы adsi, adsisearcher, wmi, wmiclass и wmisearcher
Благодаря тому что Windows Compatibility Pack для .NET Core теперь является частью PowerShell Core 6.1, мы можем использовать такие классы, как System.DirectoryServices.DirectoryEntry, System.DirectoryServices.DirectorySearcher, System.Management.ManagementObject, System.Management.ManagementClass и System.Management.ManagementObjectSearcher.
Однако, вместо того чтобы обращаться к ним, используя их полное имя, мы, как и в Windows PowerShell 5.1, можем воспользоваться следующими акселераторами: adsi, adsisearcher, wmi, wmiclass и wmisearcher соответственно.
Таким образом, при получении определенного объекта Active Directory вместо того, чтобы указывать имя класса System.DirectoryServices.DirectoryEntry целиком
[System.DirectoryServices. DirectoryEntry]"LDAP://CN= someuser, CN=Users, DC=somedomain, DC=ru"
мы можем задействовать акселератор adsi.
[adsi]"LDAP://CN=someuser, CN=Users, DC=somedomain, DC=ru"
Для поиска объектов в Active Directory мы можем воспользоваться акселератором adsisearcher.
$searcher = [adsisearcher]" (& (objectClass=user) (sAMAccountName=someuser))" $searcher.FindAll ()
Для получения информации о службе Netlogon вместо полного имени класса System.Management.ManagementObject мы можем указать акселератор wmi.
[wmi]"Win32_Service.Name='Netlogon'"
Если же нас заинтересует, какими свойствами и методами обладает класс Win32_Service, мы можем воспользоваться акселератором wmiclass.
[wmiclass]"Win32_Service"
А для поиска объектов WMI с определенными значениями мы можем задействовать акселератор wmisearcher.
$searcher = [wmisearcher]"select * from Win32_Process where name='pwsh.exe'" $searcher.Get ()
PSCustomObject
PSCustomObject — это пользовательский объект, который позволяет вам самостоятельно определять нужные свойства и методы, не основываясь на каком-либо существующем классе, и, как следствие, им не ограничиваясь. Создать его можно несколькими способами. Например, вот так:
[PSCustomObject]@{PropertyOne = 1; PropertyTwo = 2}
До сих пор получалось так, что, в отличие от других объектов, например процессов или служб, одиночные объекты PSCustomObject не обладали свойствами Length и Count (рисунок 19). Для чего это нужно? Наличие таких свойств может быть полезно при обработке неких поступающих значений, вне зависимости от того, являются они массивами или одиночными объектами. По сути, эти свойства позволяют вам уравнять массивы и скалярные значения и обрабатывать их, используя одну и ту же логику, без необходимости создания отдельного кода для каждого случая, как показано на рисунке 20.
Рисунок 19. Свойства одиночных объектов PSCustomObject |
Рисунок 20. Пример обработки массива и скалярной величины |
Несмотря на то что для массивов объектов типа PSCustomObject, равно как и для массивов любых других объектов, эта возможность существовала и раньше, в PowerShell Core 6.1 она стала доступной и для одиночных объектов PSCustomObject (рисунок 21). Кроме того, одиночные объекты PSCustomObject теперь также поддерживают использование методов ForEach и Where (рисунок 22).
Рисунок 21. Обработка одиночных объектов PSCustomObject в PowerShell Core 6.1 |
Рисунок 22. Методы ForEach и Where и одиночные объекты PSCustomObject |
Обновление справочной информации
Команда Update-Help была реализована в Windows PowerShell 3.0 с целью повышения актуальности справочной информации благодаря возможности ее обновления. Таким образом, эта команда делает внесенные в документацию изменения доступными для пользователей гораздо быстрее.
До выхода PowerShell Core версии 6.1 единственным местом хранения справочной информации был каталог модуля, работу команд которого она описывала, хотя и с некоторыми особенностями для модулей, являющихся частью PowerShell, таких, например, как Microsoft.PowerShell.Management. А так как все системные модули располагаются в каталогах установки PowerShell, для Windows PowerShell это C:\Windows\System32\WindowsPowerShell\v1.0, а в случае PowerShell Core — каталог, расположенный в C:\Program Files\PowerShell, это делало невозможным обновление справочной информации пользователем, не обладающим правами администратора.
Кроме того, пользователь без административных прав не имел возможности обновить файлы справки для модулей, расположенных в каталогах C:\Program Files\WindowsPowerShell\Modules и C:\Program Files\PowerShell\Modules.
Хотя стоит сказать, что модулей, установленных в профиле пользователя, — C:\Users\Documents\WindowsPowerShell и C:\Users\Documents\PowerShell, это ограничение не касалось.
Теперь же, при работе в PowerShell Core 6.1, кроме своего обычного местоположения, файлы справки могут быть сохранены и в пользовательском профиле, в каталоге C:\Users\username\Documents\Power
Shell\Help, что делает возможным обновление пользователем справки для встроенных модулей под своей учетной записью.
Входящая в PowerShell Core 6.1 команда Update-Help теперь по умолчанию сохраняет справочную информацию модулей в профиле пользователя. Для того чтобы сохранить файлы справки в каталоге модуля, что сделает их доступными для всех пользователей системы (если он, опять же, установлен не в профиле определенного пользователя), потребуется задействовать параметр Scope со значением AllUsers.
Update-Help -Scope AllUsers
Так как C:\Windows\System32\WindowsPowerShell\v1.0\Modules теперь входит в число каталогов, используемых PowerShell Core для поиска информации о модулях, то пользователь точно так же может обновить документацию и для модулей, доступных ранее только из Windows PowerShell. Естественно, воспользоваться он ею сможет тоже только из PowerShell Core 6.1.
Update-Help -Module NetAdapter
В целом мы можем обновить файлы справки для модулей, расположенных в любом месте. Для этого нужно, чтобы либо они были расположены в каталоге, присутствующем в переменной среды $Env: PSModulePath, и явным образом поддерживали работу в PowerShell Core (как вы помните, для этого свойство CompatiblePSEditions манифеста модуля должно содержать значение Core) либо перед обновлением справки нужный модуль был импортирован.
К примеру, мы установили некий модуль — SomeModule — в каталог C:\Program Files\WindowsPowerShell\Modules, по умолчанию недоступный для использования из PowerShell Core 6.1.
Мы можем добавить этот каталог к переменной среды $Env: PSModulePath при помощи входящей в упомянутый выше модуль WindowsCompatibility команды Add-WindowsPSModulePath. Затем, если он не указан как совместимый с PowerShell Core, импортировать его явным образом при помощи команды Import-Module с параметром SkipEditionCheck, поскольку автоматического его импорта в этом случае не произойдет (если же он содержит значение Core в CompatiblePSEditions, этот шаг можно пропустить), и инициировать обновление его справочной информации при помощи уже известной нам команды Update-Help (рисунок 23).
Рисунок 23. Обновление справочной информации для вновь установленного модуля |
Длительность выполнения команды
Мы можем получить список вызванных нами команд при помощи команды PowerShell Get-History. Возвращаемые этой командой объекты Microsoft.PowerShell.Commands.HistoryInfo до выхода PowerShell Core 6.1 обладали только пятью свойствами: Id, CommandLine, ExecutionStatus, StartExecutionTime и EndExecutionTime. Для того чтобы определить, сколько времени выполнялась та или иная команда, нам приходилось вычислять разность между свойствами EndExecutionTime и StartExecutionTime. Теперь к объекту HistoryInfo добавлено свойство Duration, значение которого соответствует количеству времени, затраченного на выполнение команды.
Соответственно, получить информацию о длительности выполнения предыдущей команды мы можем таким образом, как показано на рисунке 24.
Рисунок 24. Информация о длительности выполнения команды |
Изменения в командах PowerShell
Рассмотрим теперь изменения для некоторых команд PowerShell.
Test-Connection. Команда Test-Connection использовалась в Windows PowerShell для проверки доступности хостов по сети. В PowerShell Core 6.1 она появилась вновь. Теперь, кроме существовавшей и ранее возможности проверки доступности узлов с использованием запроса Echo Request протокола ICMP, например:
Test-Connection -TargetName somehost
и использования различных вспомогательных параметров (BufferSize — размер отправляемого пакета, Count — количество отправляемых пакетов, Delay — задержка между пакетами, MaxHops — количество переходов, параметр, определяющий, через какое количество маршрутизаторов пакет может пройти, пока не будет отброшен, Quiet — параметр, позволяющий получить в качестве результата выполнения команды значение True или False в зависимости от доступности нужного хоста), эта команда предоставляет несколько новых возможностей (рисунок 25).
Рисунок 25. Пример запуска Test-Connection |
Например, подобно параметру -t утилиты ping.exe вы теперь можете указать параметр Continues. Это приведет к тому, что команда будет выполняться до тех пор, пока вы не нажмете сочетание клавиш Ctrl + C.
Test-Connection -TargetName somehost -Continues
Также команда Test-Connection позволяет указать параметр DontFragment, запрещающий фрагментацию пакета на пути его следования, что вкупе с параметром BufferSize может пригодиться в том случае, если вы хотите удостовериться, что MTU — Maximum Transmission Unit — на пути между вами и конечным пунктом не меньше определенного значения. В данном случае если MTU между вами и неким хостом равен 1480 (или больше), то проверка доступности этого узла завершится успехом, если же нет — узел будет недоступен.
Test-Connection -TargetName somehost -BufferSize 1480-DontFragment
Если вас интересует не проверка какого-то определенного значения, а получение действительного MTU на пути следования пакетов, то в этом вам поможет параметр MTUSizeDetect.
Test-Connection -TargetName somehost -MTUSizeDetect
Команда Test-Connection теперь включает в себя некоторые возможности, ранее доступные только при использовании команды Test-NetConnection, входящей в модуль NetTCPIP, например трассировку маршрута
Test-Connection -TargetName somehost -Traceroute
или проверку доступности определенного порта.
Test-Connection -TargetName somehost -TCPPort 5985
Кроме того, команда Test-Connection теперь позволяет указать время ожидания ответа на каждый из отправленных запросов в том случае, если значение по умолчанию, равное пяти секундам, вам не подходит, например по причине низкой скорости или значительной загруженности сети.
Test-Connection -TargetName somehost -TimeoutSeconds 10
Test-Json. Новая команда Test-Json позволяет протестировать объект Json — JavaScript Object Notation — как на правильность формата в целом, так и на соответствие определенной схеме (рисунок 26).
Рисунок 26. Команда Test-Json позволяет протестировать объект Json |
Invoke-WebRequest и Invoke-RestMethod. Команды PowerShell Invoke-WebRequest и Invoke-RestMethod претерпели следующие изменения. Теперь по умолчанию, если кодовая страница для ответа в формате Json не указана, будет использоваться UTF-8.
Параметр SkipHeaderValidation позволяет задействовать не соответствующие стандартам заголовки Content-Type.
Добавлен параметр Form, упрощающий использование ключа multipart/form-data в веб-запросах, что в версии 6.0 требовало несколько больших усилий (рисунок 27).
Рисунок 27. Использование параметра Form в версии 6.0 |
Обработка ключей свойства RelationLink в ответах на запросы теперь не чувствительна к регистру, что соответствует стандартам.
Добавлен параметр Resume, позволяющий возобновить прерванную загрузку файла.
Добавлены параметры MaximumRetryCount и RetryIntervalSec, позволяющие в случае недоступности веб-сервера указать максимальное количество повторных запросов и величину интервала между их выполнением.
Where-Object. В PowerShell Core 6.1 среди параметров команды PowerShell Where-Object появился параметр Not. Может показаться, что механизм его использования состоит в том, чтобы, к примеру, добавив его в первое выражение на рисунке 28 так, как во втором выражении на рисунке, получить результат, обратный тому, который будет возвращен, если Not в выражении будет отсутствовать.
Рисунок 28. Пример команды PowerShell Where-Object |
Однако это не так, и, к слову, попытка выполнить команду во втором выражении на рисунке 28 завершится ошибкой. В этом случае мы так же, как и раньше, вместо Eq можем использовать оператор Ne, что показано в третьем выражении на рисунке.
То же самое касается и других параметров: Like, Match, Contains, In и Is. Каждый из них обладает параметром, инвертирующим получаемый результат, таким как NotLike, NotMatch, NotContains, NotIn и IsNot соответственно.
Параметр Not нужен для того, чтобы проверять поступающие объекты на соответствие значениям $Null, $False или пустой строке. Например, как на рисунке 29.
Рисунок 29. Параметр Not для проверки поступающих объектов |
В данном случае в качестве результата команда возвратила все объекты, в которых свойство с именем ‘three’ либо отсутствует, либо равняется $Null, $False или пустой строке. Фактически это выражение является зеркальным по отношению к приведенному на рисунке 30, которое возвращает все объекты, где свойство three не только присутствует, но и обладает определенным, не равным указанному выше, значением.
Рисунок 30. Выражение, зеркальное по отношению к выражению на рисунке 28 |
Как мы можем предположить, Not также доступен нам при использовании выражения, указываемого в виде значения параметра FilterScript, как видно из первого выражения на рисунке 31. Возможна запись еще короче, она показана во втором выражении на рисунке.
Рисунок 31. Два варианта записи выражения с FilterScript |
С точки зрения практического применения этот параметр может нам пригодиться при поиске неких объектов, определенное свойство которых не содержит какого-либо значения. Например, чтобы получить список запущенных процессов с отсутствующим описанием (пустым значением свойства Description), мы можем воспользоваться следующей командой:
Get-Process | Where-Object -Not Description
Для получения сетевых интерфейсов с отключенным DHCP — Dynamic Host Configuration Protocol — нам может пригодиться такая команда:
Get-NetIPInterface | Where-Object -Not Dhcp
Measure-Object. Команда Measure-Object теперь, кроме количества (Count), среднего значения (Average), суммы (Sum), максимального и минимального значений (Maximum и Minimum соответственно) возвращает и значение стандартного отклонения — StandardDeviation.
Кроме того, команда Measure-Object теперь обладает новым параметром AllStats, использование которого позволяет вывести все вычисляемые значения без необходимости указывать каждое из них в отдельности. Таким образом, две приведенные на рисунке 32 команды являются равноценными. Результат выполнения любой из них будет таким, как показано на рисунке 33.
Рисунок 32. Measure-Object теперь обладает новым параметром AllStats |
Рисунок 33. Результат выполнения команд на рисунке 32 |
Кроме того, теперь команда Measure-Object в качестве значения параметра Property, помимо объекта строки, позволяет указать и блок сценария. Например, чтобы вместе с количеством запущенных процессов подсчитать количество используемых ими потоков, мы можем воспользоваться командой, приведенной на рисунке 34.
Рисунок 34. Подсчет количества запущенных процессов и используемых ими потоков |
Оператор Replace. Оператор replace теперь поддерживает указание блока сценария в качестве аргумента. Для чего это может нам понадобиться? К примеру, у нас есть строка, содержащая как буквы, так и цифры. И каждую из этих цифр мы хотим увеличить на 2. Раньше для этого приходилось использовать класс .NET System.Text.RegularExpressions.Regex, хотя чаще всего мы к нему обращались посредством акселератора regex. Например, так, как показано на рисунке 35.
Рисунок 35. Обращение к классу .NET System.Text.RegularExpressions.Regex |
Теперь мы можем это сделать при помощи оператора replace, как на рисунке 36. Кроме того, в качестве аргумента оператора replace мы можем указать объект System.Text.RegularExpressions.MatchEvaluator, как на рисунке 37, или статический метод определенного класса, как на рисунке 38.
Рисунок 36. Обращение при помощи оператора replace |
Рисунок 37. В качестве аргумента replace указан объект System.Text.RegularExpressions.MatchEvaluator |
Рисунок 38. В качестве аргумента replace указан метод определенного класса |
Set-Location. В PowerShell Core 6.1 если мы введем команду ‘Set-Location -’ или ее сокращенный вариант ‘cd -’, то переместимся в ту папку, где находились перед тем, как перейти в текущий каталог. Последующие вызовы этой команды продолжат перемещать нас назад по истории просмотренных нами папок.
PS C:\> cd SomeFolder PS C:\SomeFolder> cd - PS C:\>
Однако, если в той папке, где вы сейчас находитесь, присутствует каталог '-' и ваша цель заключается в том, чтобы в него попасть, а не перейти в открытую ранее папку, то потребуется указать его полный путь либо относительно текущей папки, представленной символом точки, либо от корня диска.
[6.1.0] PS C:\> cd./- [6.1.0] PS C:\->
Стоит добавить, что команда 'cd +' в версии 6.1.0 недоступна и ожидается в следующих релизах.
Select-Object. У команды Select-Object, в дополнение к параметру Index, появился новый параметр SkipIndex, который позволяет пропустить определенные элементы, как на рисунке 39.
Рисунок 39. Параметр SkipIndex команды Select-Object |
Get-PfxCertificate. Команда Get-PfxCertificate теперь поддерживает указание пароля, как на рисунке 40.
Рисунок 40. Get-PfxCertificate поддерживает указание пароля |
ConvertTo-Json. Команда ConvertTo-Json в новой версии обладает параметром AsArray, который указывает, что команда должна возвращать массив даже в том случае, если в качестве входных данных был предоставлен всего один объект, как на рисунке 41.
Рисунок 41. ConvertTo-Json обладает параметром AsArray |
Get-ChildItem. Команда Get-ChildItem при получении информации о сертификатах теперь по умолчанию выводит значение EnhancedKeyUsageList, как на рисунке 42.
Рисунок 42. Команда Get-ChildItem выводит значение EnhancedKeyUsageList |
Псевдоним LP. Все команды PowerShell, обладающие параметром LiteralPath, теперь также поддерживают и его псевдоним (alias) — LP. Например:
Get-ChildItem -LP C:\
Add-Type. Команда PowerShell Add-Type больше не поддерживает Visual Basic.
Ввод команд по нажатию Tab
Теперь вы можете использовать клавишу Tab при выборе свойств объектов в команде, следующей в конвейере за Select-Object. Например, так.
Get-Process | Select-Object -First 20 | Format-List -Property
Завершение по клавише Tab работает с аргументами оператора вызова (call operator — &) в тех случаях, когда часть пути представлена переменной. Например, нажатие Tab после введения следующей части команды предложит вам варианты ее завершения.
& "$PSHOME\pw
Новые параметры pwsh.exe
Сам исполняемый файл PowerShell Core — pwsh.exe (на платформах Linux и macOS — pwsh) — теперь также поддерживает несколько новых параметров.
WorkingDirectory. При помощи параметра WorkingDirectory (или его сокращенного варианта wd) вы можете указать рабочий каталог PowerShell Core.
Например, для запуска PowerShell в каталоге вашего профиля можно применить следующую команду:
pwsh.exe -WorkingDirectory ~
SettingsFile. При помощи параметра SettingsFile (или его сокращенного варианта Settings) вы можете указать альтернативный файл настроек вместо используемого по умолчанию powershell.config.json, расположенного в каталоге установки PowerShell Core.
pwsh.exe -SettingsFile c:\SomeSettings.json
Мелкие изменения
Далее вкратце рассмотрим более мелкие изменения.
Запуск от имени администратора. Если мы закрепим ярлык Windows PowerShell на панели задач, то можем щелкнуть по нему правой кнопкой мыши и выбрать, хотим ли мы запустить консоль с правами обычного пользователя или же администратора. Теперь эта возможность доступна и для PowerShell Core 6.1.
Ярлыки в контекстном меню. При установке PowerShell Core 6.1 с использованием дистрибутива в формате msi вы можете указать параметр «Add ‘Open here’ context menus to Explorer», что позволит вам после завершения установки открывать консоль PowerShell в нужном каталоге, щелкнув на нем в проводнике правой кнопкой мыши и в открывшемся контекстном меню выбрав PowerShell 6 и затем Open here или Open here as Administrator.
Изменение кодировки манифеста модуля. Модуль манифеста, создаваемый командой PowerShell New-ModuleManifest, теперь вместо UTF-16 использует кодировку UTF-8 без маски порядка байтов (Byte Order Mask, BOM).
Отключение телеметрии. PowerShell Core использует телеметрию для отправки в Microsoft данных об операционной системе, ее версии и версии PowerShell. Раньше для ее отключения вы могли удалить файл DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY, расположенный в каталоге установки. В PowerShell Core 6.1 этот файл отсутствует. Теперь для того, чтобы отключить телеметрию, вам потребуется создать переменную среды с именем POWERSHELL_TELEMETRY_OPTOUT и значением true, yes или 1. Например, так, как показано на рисунке 43.
Рисунок 43. Отключение телеметрии |
PowerShellGet. Модуль PowerShellGet, предназначенный для взаимодействия с PowerShell Gallery, обновлен до версии 2.0. И хотя по причине практически одновременного выхода эта версия не вошла в PowerShell Core 6.1 (релиз включает в себя версию 1.6.7), обновленный модуль PowerShellGet в составе PowerShell рано или поздно безусловно появится.
Если же вы стараетесь использовать последние версии модулей, то можете загрузить его из PowerShell Gallery. Сделать это можно как для PowerShell Core, так и для Windows PowerShell.
Важное отличие версии 2.0 от предыдущих состоит в том, что теперь при использовании команд Install-Module и Install-Script место, куда будет установлен модуль или файл сценария, зависит от нескольких факторов. В Windows PowerShell версии 5.1 и ниже, запущенном от имени администратора, вызов команды Install-Module по умолчанию установит определенный модуль в каталог C:\Program Files\WindowsPowerShell\Modules, где он будет доступен для всех пользователей системы.
Если же мы выполним эту команду в консоли Windows PowerShell, запущенной с правами пользователя, модуль будет установлен в профиле пользователя C:\Users\someuser\Documents\WindowsPowerShell\Modules.
Что касается PowerShell Core, то, будучи вызванной в любой его версии начиная с 6.0, команда Install-Module по умолчанию установит нужный модуль в профиле пользователя (для Windows это C:\Users\someuser\Documents\PowerShell\Modules), вне зависимости от того, с какими правами PowerShell был запущен.
Для того чтобы в PowerShell Core установить модуль таким образом, чтобы он был доступен для всех пользователей системы, то есть поместить его в каталог C:\Program Files\PowerShell\Modules, нам потребуется воспользоваться новым параметром Scope со значением AllUsers.
Install-Module -Name SomeModule -Scope AllUsers
То же самое касается и команды для установки файлов сценариев Install-Script.
Поддержка PowerShell Core 6.0
В соответствии с положениями Microsoft о поддержке PowerShell Core, каждая предыдущая версия будет поддерживаться в течение шести месяцев с момента выхода новой. Таким образом, PowerShell Core 6.0 будет поддерживаться ровно шесть месяцев, начиная с даты выхода версии 6.1 — 13 сентября 2018 года Соответственно, его официальная поддержка завершится 13 марта 2019 года.
Тем не менее это не повод откладывать переход на версию PowerShell Core 6.1, и я надеюсь, что среди всей приведенной в статье информации вы найдете несколько аргументов и для себя.