Разработка и распространение модуля на Powershell

Разработка и распространение модуля на Powershell

Несмотря на то, что в интернете вы можете найти очень много различных инструкций по поводу того, как создать свой собственный Powershell-модуль, даже официальная документация не дает полного понимания, как все-таки создать модуль правильно.

Я потратил несколько часов на изучение разных статей и, как обычно, пришел к своему подходу, который мне кажется достаточно удобным, гибким, и которым я хочу поделиться сейчас.

Придумайте название

Это важно :-). Потом с этим названием вы будете долго жить, поэтому придумайте то, что вам потом будет приятно видеть каждый день =).

В моем случае я решил придерживаться следующего подхода: <код_заказчика\название заказчика>.<код_проекта>.Powershell.

Для целей этого гайда давайте делать модуль My.OwnModule.Powershell.

Придумайте префикс для названия командлетов\функций

Если вы разрабатываете несколько разных модулей (например, для разных компаний или команд), иногда в модулях может быть одна и та же функция. И если вы начнете сами использовать эти модули одновременно, при их импорте начнутся конфликты имен. Поэтому имеет смысл использовать для каждого модуля свой уникальный префикс.

В нашем примере я буду использовать MyOwn. Например стандартное имя New-Item превратится в New-MyOwnItem.

Установите необходимые утилиты

Кроме самого Powershell, Вам понадобится утилита командной строки nuget. Она будет нужна, чтобы паковать модуль в nuget-пакет и распространять модуль между другими компьютерами\пользователями.

Создайте дерево каталогов

Кроме корневой папки, которая будет называться так же, как и сам модуль, понадобится начальный набор каталогов.

D:.
└───My.OwnModule.Powershell
    ├───images
    ├───private
    ├───public
    │   └───common
    └───_bin

  • images. Тут будет лежать иконка для пакета, которая в теории будет видна в каком-нибудь репозитории типа Artifactory.
  • private. Тут будут лежать скрипты, которые должны быть доступны только для служебных нужд. Например, чтобы прочитать файл с диска с обработкой ошибок.
  • public. Тут будут лежать скрипты, в которых будут доступны непосредственно пользователям модуля.
    • public -> common. Эта папка нужна исключительно для структурирования и группировки файлов. Все внутри Public будет читаться рекурсивно.
  • _bin. Тут будут лежать пакеты с модулем, когда утилита nuget скомпилирует пакет.

Создайте необходимые файлы

Также нужно создать файлы, которые собственно и превращают набор Powershell-сриптов в модуль.

D:.
│   LICENSE
│   PSScriptAnalyzerSettings.psd1
│   README.md

└───My.OwnModule.Powershell
    │   local-build.ps1
    │   local-install.ps1
    │   My.OwnModule.Powershell.nuspec
    │   My.OwnModule.Powershell.psd1
    │   My.OwnModule.Powershell.psm1
    │
    ├───images
    │       icon.png
    │
    ├───private
    │       _stub.ps1
    │
    ├───public
    │   └───common
    │           Read-MyOwnJsonFile.ps1
    │
    └───_bin

Нас интересуют файлы, которые лежат в корневой папке модуля, в private и public. Остальные - это служебные файлы git-репозитория. Ниже привожу содержимое каждого файла с комментариями.

Заполняем служебные файлы для Powershell-модуля

My.OwnModule.Powershell.nuspec

Этот файл нужен, чтобы nuget генерировал пакет.

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata>
    <id>My.OwnModule.Powershell</id>
    <version>0.0.2</version>
    <authors>Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <icon>images\icon.png</icon>
    <description>
      There is no any description available at this time. Sorry for that.
    </description>
    <releaseNotes>Initial release.</releaseNotes>
    <tags>PSEdition_Core PSEdition_Desktop Linux Mac PSModule PSIncludes_Cmdlet</tags>
  </metadata>
</package>

My.OwnModule.Powershell.psd1

Этот файл - манифест, описание модуля с точки зрения самого Powershell. Тут хранятся различные сведения об авторе, о функциях, которые модуль будет предосталять и т.п.

Обратите внимание на строку 11 и параметр FunctionsToExport. Это функции, которые будут доступны пользователям вашего модуля. Поэтому, при добавлении новых функций в модуль, необходимо помнить и добавлять их сюда.

@{
    RootModule           = "My.OwnModule.Powershell.psm1"
    ModuleVersion        = "0.0.2"
    CompatiblePSEditions = "Desktop", "Core"
    GUID                 = "8f37ba7b-be77-4b6e-8ceb-d30c0c328674"
    Author               = "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript."
    PowerShellVersion    = "7.0"

    ScriptsToProcess     = @();
       
    FunctionsToExport    = @(
        "Read-MyOwnJsonFile"
    );
    CmdletsToExport      = "*"
    VariablesToExport    = "*"
    AliasesToExport      = "*"
}

My.OwnModule.Powershell.psm1

Этот файл - скрипт, который выполняется, когда вы запускаете (или сама система запускает) Import-Module. Это самый главный файл в модуле, вообще говоря, это и есть сам модуль.

#Requires -Version 7.0


$public  = @( Get-ChildItem -Path $PSScriptRoot\public\*.ps1 -Recurse; );
$private = @( Get-ChildItem -Path $PSScriptRoot\private\*.ps1 -Recurse; );


# Dot source the files
foreach ($import in @($public + $private))
{
    try
    {
        Write-Verbose "Importing '$($import.FullName)'.";
        . $import.FullName;
    }
    catch
    {
        Write-Error -Message "Failed to import function $($import.fullname): $_";
    }
}


Export-ModuleMember -Function $public.Basename;

_stub.ps1

Я положил этот файл-заглушку, чтобы скрипт из psm1-файла смог нормально прочитать папку без возможных проблем. А вообще он полностью пустой.

Read-MyOwnJsonFile.ps1

Это файл командлета, который мы будем предоставлять нашим модулем. Обратите внимание, как он называется - Read-MyOwnJsonFile, всмысле что используется префикс для имен командлетов модуля.

local-build.ps1

Этот файл не является непосредственной частью Powershell-модуля. Это скрипт, который я использую для упаковки модуля в nuget-пакет, чтобы потом его можно было положить куда-нибудь в архив. Также этот скрипт в каждый запуск изменяет версию модуля на +1.

# Config
$moduleName = "My.OwnModule.Powershell";


# Clear old packages
# Get-ChildItem .\$moduleName\_bin | Remove-Item -Force -Verbose;


#region Get current package version and increment Patch
$version = Select-String -Path .\$moduleName\$moduleName.nuspec -Pattern "<version>(\d)\.(\d)\.(\d{1,})</version>";
[int]$majorVersion = $version | Select-Object @{name="version"; expression={$_.Matches.Groups[1].Value}} | select-object -ExpandProperty version;
[int]$minorVersion = $version | Select-Object @{name="version"; expression={$_.Matches.Groups[2].Value}} | select-object -ExpandProperty version;
[int]$patchVersion = $version | Select-Object @{name="version"; expression={$_.Matches.Groups[3].Value}} | select-object -ExpandProperty version;
$patchVersion++;
$nuspecVersionString = "<version>$majorVersion.$minorVersion.$patchVersion</version>";
$psd1VersionString = "ModuleVersion        = `"$majorVersion.$minorVersion.$patchVersion`"";
#endregion /Get current package version and increment Patch


#region Update package version
$a = Get-Content -Path ".\$moduleName\$moduleName.nuspec" | %{$_ -replace "<version>(\d)\.(\d)\.(\d{1,})<\/version>", $nuspecVersionString };
$a | Out-File ".\$moduleName\$moduleName.nuspec" -Verbose;

$a = Get-Content -Path ".\$moduleName\$moduleName.psd1" | %{$_ -replace "ModuleVersion        = `"\d\.\d.\d{1,}`"", $psd1VersionString };
$a | Out-File ".\$moduleName\$moduleName.psd1" -Verbose;
#endregion /Update package version


nuget pack ".\$moduleName\$moduleName.nuspec" -OutputDirectory .\$moduleName\_bin -Properties NoWarn=NU5111,NU5110,NU5100
$package = Get-ChildItem .\$moduleName\_bin\*.nupkg | Sort-Object -Property CreationTime | Select-Object -Last 1;

$package

local-install.ps1

Соответственно, этот кастомный скрипт - для установки модуля.

$moduleName = "My.OwnModule.Powershell";
$repoName = "My.OwnModule.Powershell.Repository";
$repoPath = "D:\Private\My.OwnModule.Powershell\My.OwnModule.Powershell\_bin\";

Register-PSRepository -Name $repoName -SourceLocation $repoPath -InstallationPolicy Trusted -ScriptSourceLocation $repoPath;

Install-Module -Name $moduleName -Repository $repoName -Verbose;

Get-Module $moduleName -ListAvailable;

Упаковка модуля

Попробуем запустить local-build.ps1 и посмотреть, что получится.

Разработка и распространение модуля на Powershell

Отлично! Nuget-пакет готов и лежит в папке My.OwnModule.Powershell\_bin\My.OwnModule.Powershell.0.0.3.nupkg. Попробуем его установить и воспользоваться.

Установка Powershell-модуля из nuget-пакета.

Разработка и распространение модуля на Powershell

Прекрасно, модуль готов к работе!

Там Verbose говорит, что версия 0.0.5 уже установлена и так далее. Это потому что я попытался понизить версию, вместо того, чтобы повысить. Не обращайте внимание.

GitHub репозиторий

Вы можете найти все эти файлы в моем репозитории: https://github.com/vicioussn/My.OwnModule.Powershell.

powershell (ru)

  • Просмотров: 871
Добавить комментарий

Related Articles