Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Недавно у меня была идея модуля, который я хотел реализовать как двоичный модуль. Я еще не создал его с помощью библиотеки PowerShell Standard, поэтому это представляется хорошей возможностью. Я использовал руководство по созданию кроссплатформенного двоичного модуля, чтобы создать этот модуль без каких-либо затруднений. Мы будем ходить по этому же процессу, и я добавлю немного дополнительных комментариев на пути.
Заметка
Оригинальная версия этой статьи появилась в блоге, написанном @KevinMarquette. Команда PowerShell благодарит Кевина за предоставление этого содержимого нам. Пожалуйста, ознакомьтесь с его блогом на PowerShellExplained.com.
Что такое стандартная библиотека PowerShell?
Стандартная библиотека PowerShell позволяет создавать кроссплатформенные модули, работающие как в PowerShell, так и в Windows PowerShell 5.1.
Почему двоичные модули?
Когда вы пишете модуль на C#, вы теряете простой доступ к командлетам и функциям PowerShell. Но если вы создаете модуль, который не зависит от многих других команд PowerShell, преимущество производительности может быть значительным. PowerShell оптимизирован для администратора, а не для компьютера. Перейдя на C#, вы сможете избавиться от накладных расходов, свойственных PowerShell.
Например, у нас есть критически важный процесс, который работает с JSON и хэш-файлами. Мы оптимизировали PowerShell столько, сколько мы могли бы, но процесс по-прежнему занимает 12 минут. Модуль уже содержал много PowerShell-кода в стиле C#. Это делает преобразование в двоичный модуль чистым и простым. Преобразовав в двоичный модуль, мы сократили время процесса свыше 12 минут до четырех минут.
Гибридные модули
Двоичные командлеты можно использовать в сочетании с расширенными функциями PowerShell. Все, что вы знаете о модулях скриптов, применяется так же. Пустой файл psm1 включен, чтобы добавить другие функции PowerShell позже.
Почти все скомпилированные командлеты, которые я создал, изначально были функциями PowerShell. Все наши двоичные модули — это действительно гибридные модули.
Сборка скриптов
Я держал скрипт сборки простым здесь. Обычно я использую большой скрипт Invoke-Build в рамках конвейера CI/CD. Это делает больше магии, как запуск тестов Pester, запуск PSScriptAnalyzer, управление версиями и публикация в PSGallery. Когда я начал использовать скрипт сборки для своих модулей, я смог найти много вещей, которые нужно добавить в него.
Планирование модуля
План для этого модуля — создать папку src для кода C# и структурировать остальные, как для модуля скрипта. Это включает использование скрипта сборки для компиляции всего в папку Output. Структура папок выглядит следующим образом:
MyModule
├───src
├───Output
│ └───MyModule
├───MyModule
│ ├───Data
│ ├───Private
│ └───Public
└───Tests
Начало работы
Сначала нужно создать папку и создать репозиторий Git. Я использую $module в качестве заполнителя для имени модуля. Это позволит вам повторно использовать эти примеры при необходимости.
$module = 'MyModule'
New-Item -Path $module -Type Directory
Set-Location $module
git init
Затем создайте папки корневого уровня.
New-Item -Path 'src' -Type Directory
New-Item -Path 'Output' -Type Directory
New-Item -Path 'Tests' -Type Directory
New-Item -Path $module -Type Directory
Настройка двоичного модуля
Эта статья посвящена двоичному модулю, и с него мы начнем. В этом разделе приводятся примеры из руководства по созданию кроссплатформенного двоичного модуля. Ознакомьтесь с этим руководством, если вам нужны дополнительные сведения или возникли проблемы.
Сначала нужно проверить версию SDK dotnet core, который у нас установлен. Я использую 2.1.4, но вы должны иметь 2.0.0 или более поздней версии, прежде чем продолжить.
PS> dotnet --version
2.1.4
Я веду работу из папки src для этого раздела.
Set-Location 'src'
С помощью команды dotnet создайте библиотеку классов.
dotnet new classlib --name $module
Это создало проект библиотеки в вложенной папке, но я не хочу этого дополнительного вложения. Я собираюсь переместить эти файлы на уровень.
Move-Item -Path .\$module\* -Destination .\
Remove-Item $module -Recurse
Задайте версию пакета SDK для .NET Core для проекта. У меня есть пакет SDK 2.1, поэтому я собираюсь указать 2.1.0.
Используйте 2.0.0, если вы используете пакет SDK 2.0.
dotnet new globaljson --sdk-version 2.1.0
Добавьте в проект пакет NuGet стандартной библиотеки PowerShell . Убедитесь, что вы используете последнюю версию, доступную для уровня совместимости, который требуется. Я бы выбрал последнюю версию по умолчанию, но я не думаю, что этот модуль использует какие-либо функции, появившиеся после PowerShell 3.0.
dotnet add package PowerShellStandard.Library --version 7.0.0-preview.1
У нас должна быть папка src, которая выглядит следующим образом:
PS> Get-ChildItem
Directory: \MyModule\src
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/14/2018 9:51 PM obj
-a---- 7/14/2018 9:51 PM 86 Class1.cs
-a---- 7/14/2018 10:03 PM 259 MyModule.csproj
-a---- 7/14/2018 10:05 PM 45 global.json
Теперь мы готовы добавить собственный код в проект.
Создание двоичного командлета
Необходимо обновить src\Class1.cs, чтобы он содержал этот начальный командлет:
using System;
using System.Management.Automation;
namespace MyModule
{
[Cmdlet( VerbsDiagnostic.Resolve , "MyCmdlet")]
public class ResolveMyCmdletCommand : PSCmdlet
{
[Parameter(Position=0)]
public Object InputObject { get; set; }
protected override void EndProcessing()
{
this.WriteObject(this.InputObject);
base.EndProcessing();
}
}
}
Переименуйте файл в соответствии с именем класса.
Rename-Item .\Class1.cs .\ResolveMyCmdletCommand.cs
Затем мы можем создать наш модуль.
PS> dotnet build
Microsoft (R) Build Engine version 15.5.180.51428 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 18.19 ms for C:\workspace\MyModule\src\MyModule.csproj.
MyModule -> C:\workspace\MyModule\src\bin\Debug\netstandard2.0\MyModule.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.19
Чтобы загрузить новый командлет, можно вызвать Import-Module в новой библиотеке DLL.
PS> Import-Module .\bin\Debug\netstandard2.0\$module.dll
PS> Get-Command -Module $module
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Resolve-MyCmdlet 1.0.0.0 MyModule
Если импорт завершается сбоем в системе, попробуйте обновить .NET до версии 4.7.1 или более поздней версии. Руководство по созданию кроссплатформенного двоичного модуля содержит дополнительные сведения о поддержке и совместимости .NET для более старых версий .NET.
Манифест модуля
Это здорово, что мы можем импортировать библиотеку dll и иметь рабочий модуль. Мне нравится продолжать работать с ним и создавать манифест модуля. Нам нужен манифест, если мы хотим опубликовать в PSGallery позже.
В корне проекта мы можем выполнить эту команду, чтобы создать нужный манифест модуля.
$manifestSplat = @{
Path = ".\$module\$module.psd1"
Author = 'Kevin Marquette'
NestedModules = @('bin\MyModule.dll')
RootModule = "$module.psm1"
FunctionsToExport = @('Resolve-MyCmdlet')
}
New-ModuleManifest @manifestSplat
Я также создаю пустой корневой модуль для будущих функций PowerShell.
Set-Content -Value '' -Path ".\$module\$module.psm1"
Это позволяет смешивать обычные функции PowerShell и двоичные командлеты в одном проекте.
Создание полного модуля
Я компилирую все вместе в выходную папку. Для этого необходимо создать скрипт сборки. Как правило, я добавлю это к скрипту Invoke-Build, но мы можем сохранить его простым для этого примера. Добавьте это в build.ps1, находящееся в корневой директории проекта.
$module = 'MyModule'
Push-Location $PSScriptRoot
dotnet build $PSScriptRoot\src -o $PSScriptRoot\output\$module\bin
Copy-Item "$PSScriptRoot\$module\*" "$PSScriptRoot\output\$module" -Recurse -Force
Import-Module "$PSScriptRoot\Output\$module\$module.psd1"
Invoke-Pester "$PSScriptRoot\Tests"
Эти команды создают библиотеку DLL и помещает ее в папку output\$module\bin. Затем он копирует другие файлы модулей в нужные места.
Output
└───MyModule
├───MyModule.psd1
├───MyModule.psm1
└───bin
├───MyModule.deps.json
├───MyModule.dll
└───MyModule.pdb
На этом этапе мы можем импортировать модуль с psd1-файлом.
Import-Module ".\Output\$module\$module.psd1"
Отсюда мы можем переместить папку .\Output\$module в директорию $Env:PSModulePath, и она автоматически загрузит нашу команду каждый раз, когда это необходимо.
Обновление: dotnet new PSModule
Я узнал, что средство dotnet имеет шаблон PSModule.
Все описанные выше шаги по-прежнему допустимы, но этот шаблон исключает многие из них. Это все еще достаточно новый шаблон, который нуждается в некоторой доработке. Ожидайте, что будет становиться лучше с этого момента.
Вот как устанавливать и использовать шаблон PSModule.
dotnet new -i Microsoft.PowerShell.Standard.Module.Template
dotnet new psmodule
dotnet build
Import-Module "bin\Debug\netstandard2.0\$module.dll"
Get-Module $module
Этот минимальный жизнеспособный шаблон заботится о добавлении пакета SDK для .NET, стандартной библиотеки PowerShell и создает пример класса в проекте. Его можно создать и запустить сразу.
Важные сведения
Прежде чем мы закончим эту статью, вот несколько других деталей, которые стоит упомянуть.
Выгрузка библиотек DLL
После загрузки двоичного модуля вы не можете выгрузить его. DLL-файл блокируется, пока не выгрузите его. Это может быть раздражает при разработке, так как каждый раз, когда вы вносите изменения и хотите создать его, файл часто блокируется. Единственный надежный способ устранить эту проблему заключается в закрытии сеанса PowerShell, загруженного библиотекой DLL.
Перезагрузка окна в VS Code
Большую часть работы по разработке на PowerShell я выполняю в VS Code. Когда я работаю над двоичным модулем (или модулем с классами), я пошел в привычку перезагрузить VS Code каждый раз при сборке.
Ctrl+Shift+P отображает командное окно и Reload Window всегда находится в верхней части списка.
Вложенные сеансы PowerShell
Один из других вариантов заключается в том, чтобы иметь хорошее покрытие тестов Пестера. Затем можно настроить скрипт build.ps1, чтобы запустить новый сеанс PowerShell, выполнить сборку, выполнить тесты и закрыть сеанс.
Обновление установленных модулей
Эта блокировка может раздражать при попытке обновить локально установленный модуль. Если какой-либо сеанс его загрузил, вам нужно его найти и закрыть. Это меньше проблемы при установке из PSGallery, так как управление версиями модулей помещает новую в другую папку.
Вы можете настроить локальную PSGallery и публиковать в ней в рамках сборки. Затем выполните локальную установку из этой PSGallery. Это звучит как много работы, но это может быть так же просто, как запуск контейнера Docker. Я объясняю, как это сделать, в моей публикации на тему Использование сервера NuGet для PSRepository.
Окончательные мысли
Я не касался синтаксиса C# для создания командлета, но в пакете SDK для Windows PowerShell имеется обширная документация. Это определенно что-то, что стоит исследовать как первую ступень к более углубленному изучению C#.
PowerShell