Desarrollación y distribución de módulo de Powershell

Desarrollación y distribución de módulo de Powershell

A pesar de que en Internet podeis encontrar muchas instrucciones diferentes sobre cómo crear su propio módulo de Powershell, incluso la documentación oficial todavía no os da comprención completa de cómo escribir un módulo correctamente.

Yo pasé unos horas para estudiar varios articulos y, como de costumbre, localizé mi manera propia, que me parece bastante conveniente, flexible y que quiero compartir ahora.

Inventa el nombre

Es importante :-). Entonces, vas a vivir con este nombre durante mucho tiempo, así que piensa en algo que te alegrará ver todos los días =).

En mi caso, decidí seguir con este enfoque: <código_de_cliente\nombre_de_cliente>.<código_de_proyecto>.Powershell. Para los objetivos de esta guía, hagamos un módulo que se llama My.OwnModule.Powershell.

Inventa el prefijo para los cmdlets\funciones

Si desarrollas unos cuantos módulos (por ejemplo, para empresas o equipos diferent@s), a veces en los módulos puede ser la misma función. Y si te mismo empiezas usar estos módulos al mismo tiempo, cuando se importen, se aparecerén los conflictos de nombes de funciones. Por eso, tiene sentido usar el prefijo único para cada módulo.

En nuestro ejemplo usaré el prefijo MyOwn. Es decir, el nombre estándar New-Item se convertirá en New-MyOwnItem.

Instala las utilidades necesarias

Más álla del Poweshell mismo, os necesitará la utilidad de línea comandos nuget. Será necesaria para empaquetar el módulo en un paquete nuget y distribuirlo entre otras ordenadores\servidores y usuarios.

Crea un árbol de directorios

Aparte de la carpeta raíz, que será llamarse tanto como módulo mismo, os necesitará conjunto inicial de carpetas.

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

  • images. Aquí habrá un icono para el paquete Nuget, que en teoría será visible en algún repositorio del tipo Artifactory.
  • private. Aquí habrá unos scriptos, que deben estar disponibles solo para necesidades utilidades. Por ejemplo, para leer un archivo del disco duro con tratamiento de errores.
  • public. Aquí habrá los scriptos en los que etarán disponibles directamente para los usuarios de módulo.
    • public -> common. Esta carpeta se necesita únicamente para estructuración y agrupación de los archivos. Todos los archivos dentro de Public se leerán recursivamente.
  • _bin. Aquí es donde estarán los paquetes con el módulo cuando nuget compile el paquete.

Crea los archivos necesarios

Hay que incluso crear unos archivos, cuales de hecho y convierten un conjunto de scriptos Powershell a módulo.

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

Nos interesan los archivos que están dentro de carpeta raíz de módulo, de private y de public. Resto - son archivos utilidades de repositorio Git. A continuación se muestra el contenido de cada archivo con comentarios.

Completamos los archivos utilidades de módulo Powershell

My.OwnModule.Powershell.nuspec

Este archivo es necesario para que nuget genere el paquete.

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata>
    <id>My.OwnModule.Powershell</id>
    <version>0.0.2</version>
    <authors>Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.</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

Este archivo es un manifiesto, una descripción del módulo desde el punto de vista de Powershell. Almacena diversa información sobre el autor, sobre las funciones que proporcionará el módulo, etc.

Observe la línea 11 y el parámetro FunctionsToExport. Son las funciones que estarán disponibles para los usuarios de vuestro módulo. Por lo tanto, al agregar nuevas funciones al módulo, es necesario recordar a agregarlas aquí.

@{
    RootModule           = "My.OwnModule.Powershell.psm1"
    ModuleVersion        = "0.0.2"
    CompatiblePSEditions = "Desktop", "Core"
    GUID                 = "8f37ba7b-be77-4b6e-8ceb-d30c0c328674"
    Author               = "Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo."
    PowerShellVersion    = "7.0"

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

My.OwnModule.Powershell.psm1

Este archivo es un script que se ejecuta cuando ejecutais (o el sistema misma ejecuta) Import-Module. Este es el archivo más importante del módulo, en términos generales, este es el módulo en sí.

#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

Perdí este archivo auxiliar para que script del archivo psm1 pudiera leer la carpeta Private sin ningún problema. En general, está completamente vacío.

Read-MyOwnJsonFile.ps1

Este es el archivo de cmdlet que proporcionaremos con nuestro módulo. Observe cómo se llama - Read-MyOwnJsonFile, lo que significa que usa un prefijo para los nombres de cmdlet de módulo.

local-build.ps1

Este archivo no forma parte directamente del módulo Powershell. Esta es el script que yo utilizo para empaquetar el módulo en un paquete nuget para poder colocarlo en un archivo en alguna parte. Además, este script cambia la versión del módulo en +1 cada vez que se ejecuta.

# 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

En consecuencia, este script personalizado es para instalar el módulo.

$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;

Empaquetación de módulo

Intentemos ejecutar local-build.ps1 y veamos qué sucede.

Desarrollación y distribución de módulo de Powershell

¡Genial! Paquete Nuget está listo dentro de carpeta My.OwnModule.Powershell\_bin\My.OwnModule.Powershell.0.0.3.nupkg. Intentaremos instalarlo y usarlo.

Instalación de módulo Powershell de paquete nuget

Desarrollación y distribución de módulo de Powershell

Estupendo, ¡módulo está listo para funcionar!

Allí Verbose dice que la versión 0.0.5 ya está instalada y así sucesivamente. Esto se debe a que traté de degradar en lugar de actualizar. No prestad atencion.

Repositorio GitHub

Podéis encontrar todos estos archivos en mi repositorio GitHub: https://github.com/vicioussn/My.OwnModule.Powershell.

powershell (es)

  • Visto: 298
Add comment

Related Articles