Ruta del Módulo de PowerShell: Código Reutilizable Sin Copiar y Pegar

Trabajar con módulos de PowerShell es una pieza importante de la automatización de PowerShell. Cuando comienzas a aprender PowerShell, los primeros pasos generalmente consisten en usar comandos individuales. Esto conduce a la creación de scripts, lo que luego lleva a la creación de funciones.

Al usar funciones, puedes hacer que tus scripts sean más modulares. Esto te permite utilizar el mismo código en muchos lugares sin copiar y pegar código por todas partes. El uso de funciones te permite pasar menos tiempo haciendo la misma edición en el mismo código en todas las ubicaciones donde se utiliza. En su lugar, puedes trabajar en mejorar tu código en un solo lugar.

Para llevar las funciones al siguiente nivel, puedes combinar estas funciones en un módulo.

A module is a collection of functions in a text file with a psm1 extension. There are some optional additions, such as a module manifest and comment-based or external help that may also be included. These will be covered later on.

Prerrequisitos

I’ll be using Windows PowerShell 5.1 in this article. If you’re using an older version or PowerShell Core, your mileage may vary as to results you see.

Interactuando con Módulos

Una vez que abres una sesión de PowerShell por primera vez, comenzarás con dos módulos. El primero es Microsoft.PowerShell.Utility que contiene muchas funciones básicas de PowerShell que ya estás utilizando. El otro módulo es PSReadline. Puedes ver estos módulos iniciales usando el comando Get-Module.

Listing modules with Get-Module

Dicho esto, esta no es una lista completa de todos los módulos disponibles. Desde PowerShell 3, los módulos instalados se importarán según sea necesario. Si estás ejecutando una versión más antigua de PowerShell, deberás usar el comando Import-Module para importar primero el módulo antes de usar alguno de los comandos.

Hay momentos en los que aún querrías usar Import-Module incluso en versiones posteriores. Si quisieras importar un módulo después de que ya esté instalado, puedes usar Import-Module de esta manera:

Importing modules with Import-Module

Mientras Get-Module mostrará todos los módulos que están importados, no verás los módulos que aún no han sido importados. Luego puedes usar el parámetro ListAvailable para mostrar todos los otros módulos que están disponibles.

Listing all available modules with Get-Module -ListAvailable

No todos los Comandos se Muestran por Defecto

La propiedad ExportedCommands contiene una lista de todos los comandos disponibles que son exportados desde el módulo. Puedes ver algunas diferencias entre esta lista y lo que está en el archivo del módulo. Los comandos exportados son una característica incorporada en el manifiesto del módulo que permite al escritor dejar una función como oculta. Los autores de módulos también pueden usar el Export-ModuleMember cmdlet, pero eso está fuera del alcance de este artículo.

Los autores de módulos pueden querer ocultar una función porque está destinada a soportar otras funciones, no ser visible para el usuario. Para ocultar una función, el autor la excluiría del array FunctionsToExport en el manifiesto. Aquí puedes ver una vista ampliada de la propiedad ExportedCommands.

Viewing exported commands

Importación de Módulos

Hay muchas formas de comenzar a usar módulos. Puedes importar manualmente el módulo utilizando la ruta a los archivos del módulo. Esto te permite probar y actualizar el módulo sin tener que hacer mucho trabajo. Pero esto no permite mucha portabilidad, ya que tendrías que usar la ruta exacta al módulo. PowerShell tampoco importará automáticamente módulos que no estén en la variable $env:PSModulePath.

Importación selectiva de comandos

Puedes usar Import-Module para importar solo funciones específicas en lugar de todo el módulo, utilizando el parámetro Function. Esto puede ahorrar tiempo al importar módulos desde sistemas remotos, como los módulos de Office 365.

Todos los módulos de usuario

Los módulos instalados para todos los usuarios se colocan en C:\Program Files\WindowsPowerShell\Modules. Este directorio contiene muchos módulos preinstalados, incluidos aquellos instalados usando Install-Module con el ámbito predeterminado AllUsers.

Módulos del usuario actual

Si estás instalando un módulo pero solo quieres que lo use un usuario, existe un ámbito CurrentUser. Esto coloca los archivos del módulo en la carpeta de documentos en C:\Users\<username>\Documents\WindowsPowerShell\Modules. Esto puede ser útil en un entorno donde usas redirección de carpetas con la carpeta de documentos.

En este caso, puedes instalar un módulo en una computadora y usarlo en otra, ya que ambas compartirían la misma carpeta de documentos.

Módulos del sistema

Para mayor completitud, también existe un directorio de módulos en C:\Windows\System32\WindowsPowerShell\1.0\Modules. Aunque técnicamente, un módulo colocado en esta ruta sería importado como uno de los otros, no se recomienda, ya que está reservado para los módulos del sistema de Microsoft.

La Nomenclatura es Importante

Puedes colocar manualmente tu módulo en una de estas rutas para que esté disponible de forma predeterminada en una nueva sesión, pero debes asegurarte de seguir la nomenclatura requerida para los módulos. La carpeta en la que se colocan los archivos del módulo debe tener el mismo nombre que el archivo del módulo psm1 y el manifiesto del módulo psd1 si lo hay.

El uso de Get-Module -ListAvailable que mencionamos antes hace referencia a estas rutas. Puedes ver todas las rutas de los módulos usando $env:PSModulePath -Split ';'. Puedes notar otras rutas en la lista que las mostradas aquí. Muchos programas añaden sus propias rutas de módulos cuando se instalan. Uno de los ejemplos de esto es SQL, que tiene sus propios módulos incluidos en sus propias rutas de módulos.

Viewing module paths with $env:PSModulePath

También hay algunos módulos que instalarías con un proceso diferente. Uno de los ejemplos más significativos de esto es el módulo ActiveDirectory. Desde Windows 7 hasta Windows 10 1803, instalarías esto con el instalador de las Herramientas de Administración del Servidor Remoto (RSAT).

En versiones más nuevas de Windows 10 (1809+), esto solo está disponible a través de las Características bajo Demanda. La instalación de RSAT instala los módulos de ActiveDirectory y muchos otros que usarías para administrar otros roles de Windows. En los sistemas operativos de servidor de Windows, estos módulos se instalan a través del Administrador del Servidor.

Importando Módulos Remotos (Remoting Implícito)

Hay casos en los que no es práctico tener un módulo funcionando localmente. En cambio, es mejor conectarse a un dispositivo remoto e importar un módulo instalado en él. Cuando haces esto, los comandos se ejecutan realmente en la máquina remota. Esto se usa con frecuencia con los módulos de Office 365 de Microsoft. Muchos de ellos se conectan a un servidor de Office 365 que luego importa un módulo. Cuando ejecutas cualquiera de los comandos, se ejecutan en el servidor remoto y luego la salida se envía de vuelta a tu sesión.

Otro uso de la importación de módulos remotos es cuando no tienes el módulo instalado localmente. Esto es lo que obtendrías si no tuvieras instalado el módulo ActiveDirectory, pero intentaras importarlo.

Module not installed

Para importar un módulo remoto, primero debes crear una SesiónPSS. Puedes usar New-PSSession para crear la sesión. Luego importarías el módulo disponible en el dispositivo remoto usando el parámetro PSSession con Import-Module.

PS51> $AdminServer = New-PSSession -ComputerName $AdminServerName -Credential (Get-Credential)
PS51> Import-Module -Name ActiveDirectory -PSSession $AdminServer -Prefix 'Rmt'

Usar este método de importación de módulos remotos permite una ejecución de código más rápida en un entorno distribuido. Por ejemplo, si estás trabajando desde tu computadora, pero los servidores en los que estás trabajando están en todo Estados Unidos, puede llevar significativamente más tiempo ejecutar ciertos comandos localmente contra los servidores. Mientras que ejecutar los comandos en un servidor y enviar la salida de vuelta a tu sesión local es mucho más rápido.

Agregando un Prefijo de Módulo

También puedes agregar un prefijo a las funciones importadas desde la máquina remota. Esta opción está disponible al importar módulos locales, pero rara vez se utiliza fuera de la prueba de diferentes versiones de un módulo lado a lado.

Si ejecutas el comando de importación anterior y esto es lo que verías cuando miras los comandos:

Viewing all available commands in a module

En este caso, puedes usar un prefijo para mostrar que no es un módulo local. Esto se puede usar en casos donde estás importando un módulo que también está disponible localmente. Agregar el prefijo reduce la confusión sobre dónde se está ejecutando el código.

Eliminando Módulos

También puedes eliminar un módulo de la sesión actual sin usar Remove-Module. Esto elimina un módulo de la sesión local sin eliminar los archivos del módulo. Puedes querer usar esto en un caso en el que estabas usando una sesión remota para usar un módulo. Podrías usar Remove-Module para limpiar tu sesión y luego desconectar la sesión remota.

Removing a module from the session

Otro uso de Remove-Module es si estás haciendo cambios en un módulo y no quieres lanzar una nueva sesión de PowerShell. En este caso, usarías Remove-Module seguido de Import-Module para volver a cargarlo en tu sesión. Alternativamente, puedes usar el parámetro Force con Import-Module. Esto completará la descarga y recarga del módulo por ti.

¿Qué compone un módulo de PowerShell?

A module can consist of one or more files. To meet the minimum requirements for a module, you must have a module file. This can be a PSM1 file or any other module file such as a binary module file. To build upon that, your psm1 should have functions defined in it, or it will not be much use to anyone.

Mientras no haya requisitos sobre cómo deben verse las funciones o lo que deben hacer, hay algunas pautas. Por lo general, se prefiere tener todas las funciones en un módulo construido en torno al mismo concepto.

Los Módulos Contienen Funciones Afines

Por ejemplo, el módulo ActiveDirectory solo incluye funciones que interactúan de alguna manera con Active Directory. Por lo general, los nombres de las funciones también contienen un prefijo. Volviendo al módulo ActiveDirectory como ejemplo, todos los sustantivos en los nombres de las funciones comienzan con AD.

El uso de estas pautas ayuda con la descubribilidad de las funciones. Imagina que acabas de importar este nuevo módulo y quieres navegar por las funciones. Es mucho más fácil hacerlo si todas las funciones tienen una estructura de nombre similar. Aunque a menudo puedes ver que los módulos comienzan con PS, este prefijo está oficialmente reservado solo para los módulos de Microsoft. Probablemente no causarás un problema si usas PS al principio de tu módulo, pero podrías crear un conflicto con otro nombre de módulo.

Usando estas pautas, si tuvieras un conjunto de funciones que tuvieran que ver con interactuar con el registro, podrías tener algo como:

function Get-ATARegistryKey {...}

function Set-ATARegistryKey {...}

Manifiestos de Módulos

Para ampliar el archivo del módulo de texto, también puedes incluir un manifiesto de módulo. Estos archivos tienen una extensión PSD1 y contienen metadatos sobre el módulo. Aquí es donde incluirías información sobre el autor, la descripción del módulo, otros módulos requeridos y muchos otros atributos. Para publicar en un repositorio, es necesario tener los campos Author y Description completados.

Aquí tienes un ejemplo de un manifiesto que podríamos tener para nuestro módulo de registro:

#Manifesto del módulo para 'ATARegistry'
#Generado por: Tyler
#Generado en: 11/8/2019
@{
	#Módulo de script o archivo binario asociado con este manifiesto.
	RootModule = 'ATARegistry'
	#Número de versión de este módulo.
	ModuleVersion = '1.0'
	#Ediciones de PowerShell compatibles.
	#CompatiblePSEditions = @()
	#ID utilizado para identificar de manera única este módulo.
	GUID = 'fef619fa-016d-4b11-a09d-b222e094de3e'
	#Autor de este módulo
	Author = 'Tyler Muir'
	#Empresa o proveedor de este módulo
	CompanyName = 'Adam the Automator'
	#Declaración de derechos de autor para este módulo
	Copyright = '(c) 2019 tyler. All rights reserved.'
	#Descripción de la funcionalidad proporcionada por este módulo.
	Description = 'This is a test module.'
	#Versión mínima del motor de Windows PowerShell requerida por este módulo.
	#PowerShellVersion = ''
	#Nombre del host de Windows PowerShell requerido por este módulo.
	#PowerShellHostName = ''
	#Versión mínima del host de Windows PowerShell requerida por este módulo.
	#PowerShellHostVersion = ''
	#Versión mínima de Microsoft .NET Framework requerida por este módulo. Este requisito es válido solo para la edición de PowerShell para escritorio.
	#DotNetFrameworkVersion = ''
	#Versión mínima del tiempo de ejecución del lenguaje común (CLR) requerida por este módulo. Este requisito es válido solo para la edición de PowerShell para escritorio.
	#CLRVersion = ''
	#Arquitectura del procesador (None, X86, Amd64) requerida por este módulo.
	#ProcessorArchitecture = ''
	#Módulos que deben importarse al entorno global antes de importar este módulo.
	#RequiredModules = @()
	#Ensamblados que deben cargarse antes de importar este módulo.
	#RequiredAssemblies = @()
	#Archivos de script (.ps1) que se ejecutan en el entorno del llamador antes de importar este módulo.
	#ScriptsToProcess = @()
	#Archivos de tipo (.ps1xml) que se cargan al importar este módulo.
	#TypesToProcess = @()
	#Archivos de formato (.ps1xml) que se cargan al importar este módulo.
	#FormatsToProcess = @()
	#Módulos para importar como módulos anidados del módulo especificado en RootModule/ModuleToProcess
	#NestedModules = @()
	#Funciones para exportar desde este módulo, para un mejor rendimiento, no utilice comodines y no elimine la entrada, use una matriz vacía si no hay funciones para exportar.
	FunctionsToExport = @('Get-RegistryKey','Set-RegistryKey')
	#Cmdlets para exportar desde este módulo, para un mejor rendimiento, no utilice comodines y no elimine la entrada, use una matriz vacía si no hay cmdlets para exportar.
	CmdletsToExport = @()
	#Variables para exportar desde este móduloVariablesToExport = '*'
	#Alias para exportar desde este módulo, para un mejor rendimiento, no utilice comodines y no elimine la entrada, use una matriz vacía si no hay alias para exportar.
	AliasesToExport = @()
	#Recursos DSC para exportar desde este módulo
	#DscResourcesToExport = @()
	#Lista de todos los módulos empaquetados con este módulo
	#ModuleList = @()
	#Lista de todos los archivos empaquetados con este módulo
	#FileList = @()
	#Datos privados para pasar al módulo especificado en RootModule/ModuleToProcess. Esto también puede contener un hashtable PSData con metadatos adicionales del módulo utilizados por PowerShell.
	PrivateData = @{
		PSData = @{
			#Etiquetas aplicadas a este módulo. Ayudan con el descubrimiento del módulo en galerías en línea.
			#Tags = @()
			#URL de la licencia para este módulo.
			#LicenseUri = ''
			#URL principal del sitio web de este proyecto.
			#ProjectUri = ''
			#URL de un icono que representa este módulo.
			#IconUri = ''
			#Notas de lanzamiento de este módulo
			#ReleaseNotes = ''
		} 
		#Fin del hashtable de PSData
	} 
	#Fin del hashtable de PrivateData
	#URI de HelpInfo de este módulo
	#HelpInfoURI = ''
	#Prefijo predeterminado para los comandos exportados desde este módulo. Anule el prefijo predeterminado utilizando Import-Module -Prefix.
	#DefaultCommandPrefix = ''
}

Si bien esto puede parecer intimidante al principio, Microsoft tiene un cmdlet práctico que puedes usar para generar un manifiesto de módulo. El comando incluido es New-ModuleManifest. Para generar el manifiesto mostrado anteriormente, podrías haber utilizado:

PS51> New-ModuleManifest -Path .\Scripts\TestModule.psd1 -Author 'Tyler Muir' -CompanyName 'Adam the Automator' -RootModule 'TestModule.psm1' -FunctionsToExport @('Get-RegistryKey','Set-RegistryKey') -Description 'This is a test module.'

Archivos de Ayuda Externos

También puedes encontrar archivos de ayuda externos en algunos módulos. Se pueden identificar por el <ModuleName>-Help.xml al final del nombre del archivo. Estos archivos de ayuda externos contienen la misma información que normalmente se encontraría en la ayuda basada en comandos que podrías encontrar en la definición de una función.

Esto también requeriría que agregues # .ExternalHelp <ModulePath>-Help.xml a tu función para que funcione correctamente al usar el comando Get-Help después de importar el módulo. Por lo general, solo es común ver archivos de ayuda externos con módulos muy grandes y, debido a eso, están fuera del alcance.

Aunque estos son los tipos de archivos más comunes que verás en un módulo, no son los únicos archivos. A veces verás archivos binarios además de un módulo de texto, ya que hay otras dependencias. Al explorar a través de las rutas del módulo, puedes encontrar muchos ejemplos de tipos de archivos adicionales en los módulos.

Para publicar adecuadamente archivos de módulo no estándar, deberías incluir otros archivos en el parámetro FileList en el manifiesto de tu módulo.

Dentro del manifiesto del módulo, notarás muchos otros parámetros que actualmente están vacíos. Puedes usar estos para definir otros requisitos para usar tu módulo. Por ejemplo, puedes definir las versiones de PowerShell con las que puede funcionar el módulo. Si intentas importar el módulo en una versión no compatible de PowerShell, esto es lo que verías:

Requiring certain versions of PowerShell

PSRepositories

Una de las opciones principales de distribución para los módulos es un PSRepository. En una vista general, un PSRepository es un lugar local donde múltiples personas o múltiples dispositivos pueden acceder a los archivos del módulo. Estos son frecuentemente servidores web donde puedes publicar archivos.

También puedes usar un directorio para el repositorio, pero esto te limita en la funcionalidad de tu repositorio. Puedes alojar un PSRepository tú mismo, o puedes utilizar una de las muchas opciones disponibles en Internet como PowerShell Gallery. Puedes ver tus PSRepositories usando el comando Get-PSRepository.

Default PowerShell NuGet repositories

Por defecto, solo tendrás una entrada y será para PowerShell Gallery. Puedes notar que dirá que no es de confianza. Esto se debe a que PowerShell te hace saber que al usar PowerShell Gallery puedes estar usando código no escrito y aprobado por Microsoft. Esto significa que antes de que se instalen módulos desde allí, deberás dar permiso explícito.

Agregar PSRepositories

También puedes agregar tus propios repositorios. Para confiar en PowerShell Gallery, puedes ejecutar Get-PSRepository -Name PSGallery | Set-PSRepository -InstallationPolicy Trusted o puedes aceptar la advertencia la primera vez que instales un módulo desde PowerShell Gallery.

Todos los comandos que usarías para interactuar con estos **PSRepositories** se pueden encontrar en el módulo **PowerShellGet**. Puedes ver las funciones aquí:

Commands in the PowerShellGet module

Es posible que sea necesario actualizar el módulo **PowerShellGet** antes de interactuar con ciertos repositorios.

Búsqueda de módulos

Otra característica clave de usar un **PSRepository** es poder buscar módulos. Esto se logra usando el comando `Find-Module`. Hay varias formas de filtrar para encontrar específicamente lo que estás buscando, pero por ahora puedes buscar los módulos de VMware así:

Finding modules on the PowerShell Gallery

Esto mostrará todos los módulos que comienzan con VMware. Aunque la mayoría de estos son de VMware, necesitas mirar el atributo del autor para ver quién publicó el módulo.

Dado que cualquiera puede cargar en PowerShell Gallery, hay miles de módulos disponibles. Esto significa que puedes encontrar módulos que no funcionen correctamente para tu caso de uso. Muchos de los módulos que encontrarás son de código abierto, por lo que puedes contribuir a mejorar la funcionalidad del módulo.

Instalación de módulos

Para usar el comando `Install-Module`, debes tener un **PSRepository** de confianza que esté alojando el módulo. Esto puede ser PowerShell Gallery, otro **PSRepository** de internet o un sitio autohospedado. Puedes enviar desde el comando `Find-Module` para confirmar fácilmente el módulo antes de instalarlo.

Finding modules installed from a PSRepository

También puedes definir la versión de un módulo usando los parámetros `MinimumVersion`, `MaximumVersion` o `RequiredVersion`.

Para ver todos los módulos instalados utilizando Install-Module, puedes usar Get-InstalledModule. Esto enumerará todos los módulos instalados en el ámbito AllUsers o en tu ámbito CurrentUser.

Desinstalación de módulos

Así como puedes instalar un módulo, también puedes desinstalarlo. Si el módulo no fue instalado a través del comando Install-Module, no podrás desinstalarlo con el comando Uninstall-Module.

Uninstalling modules installed from a PSRepository with Uninstall-Module

Como puedes ver aquí, estamos intentando desinstalar el módulo ActiveDirectory. Dado que este módulo no se instaló con Install-Module, recibirías un error al intentar usar Uninstall-Module. Para desinstalar este módulo, tendríamos que desinstalarlo invirtiendo lo que usaste para instalar el módulo.

Para ver una desinstalación exitosa de un módulo, puedes desinstalar el módulo VMware.PowerCLI que instalaste anteriormente.

Uninstalling a module downloaded from the PowerShell Gallery

Aunque hayas desinstalado VMware.PowerCLI, puedes ver que todavía hay muchas dependencias instaladas. Si quisieras desinstalar todos los módulos podríamos usar Get-InstalledModule VMware.* | Uninstall-Module -Force.

La razón por la que tendrías dificultades para desinstalar completamente este módulo es porque tiene muchas dependencias. Además, algunos de estos módulos son dependencias entre sí, por lo que se requeriría el parámetro Force.

Actualización de módulos

Ahora que sabes cómo instalar y desinstalar un módulo, es posible que te estés preguntando cómo actualizar un módulo que has instalado.

Al igual que con otros procesos, si el módulo no se instaló usando Install-Module, no puedes actualizarlo utilizando los comandos de PowerShell. Puedes utilizar Update-Module para actualizar un módulo a la última versión o a una versión específica más reciente.

También hay un interruptor para AllowPreRelease, que te permite actualizar a una versión que aún no se ha lanzado oficialmente. A veces, esto puede ser útil si se ha corregido un error que estás experimentando o se ha agregado una nueva función que te gustaría utilizar.

Updating modules with Update-Module

Inspeccionar/Guardar un Módulo

Uno de los comandos menos utilizados pero muy útiles al examinar módulos antes de usarlos es Save-Module. Con este comando, puedes descargar un módulo a una ruta sin instalarlo.

Luego puedes inspeccionar los archivos y, si el módulo no es un módulo binario, puedes abrirlo y ver el código que lo compone. Esto es útil no solo para asegurarte de que un módulo no esté haciendo nada malicioso, sino también para aprender cómo otros estructuran sus módulos.

Downloading modules with Save-Module

En este ejemplo, no solo se descarga el módulo VMware.PowerCLI, sino también todas las dependencias. Esto es lo que se muestra en la carpeta de VMware.PowerCLI:

VMware.PowerCLI module contents

Este es un buen ejemplo que muestra cómo a veces hay archivos de módulos no estándar incluidos en el módulo, como el acuerdo de licencia de usuario final.

Creación de tu propio Módulo

Has visto cómo interactuar con el módulo de otra persona. Ahora quieres aprender a crear el tuyo propio para poder comenzar a optimizar tu código para escalabilidad.

Crear archivos de plantilla

Primero necesitas crear una carpeta para todos tus archivos de módulo. Después de tener el contenedor, necesitas crear tu archivo de módulo. Debes asegurarte de que tu archivo de módulo tenga el mismo nombre que tu carpeta, de lo contrario, al intentar publicar tu módulo, PowerShell no descubrirá el módulo correctamente.

PS51> New-Item -Path .\Scripts -Name ATARegistry -ItemType Directory
PS51> New-Item -Path .\Scripts\ATARegistry -Name ATARegistry.psm1

Ahora también quieres usar un manifiesto, también necesitarás nombrarlo igual que el contenedor y el archivo de módulo.

PS51> New-ModuleManifest -Path .\Scripts\ATARegistry\ATARegistry.psd1 -Author 'Tyler Muir' -CompanyName 'Adam the Automator' -RootModule ATARegistry.psm1 -Description 'Used for interacting with registry keys'

Con el contenedor, el archivo de módulo y el archivo de manifiesto, tienes un módulo completamente funcional. Podrías publicar este módulo en un PSRepository y comenzar a instalarlo donde quieras. Aunque, dado que el archivo de módulo está vacío, probablemente no te servirá mucho. Aún puedes usar estos archivos para probar la publicación y asegurarte de que tu repositorio funcione.

Registrando un PSRepository

Antes de poder publicar tu módulo, necesitarás agregar otro PSRepository a tu sesión. Para pruebas, puedes usar una ruta local como tu PSRepository ya que será fácil de configurar y desmontar.

Normalmente, si fueras a configurar un PSRepository con un directorio, querrías asegurarte de que varios equipos puedan acceder a él. Puedes crear un repositorio local de esta manera:

PS51> New-Item -Path C:\ -Name Repo -ItemType Directory
PS51> Register-PSRepository -Name 'LocalRepo' -SourceLocation 'C:\Repo' -PublishLocation 'C:\Repo' -InstallationPolicy Trusted

Si solo fueras a descargar desde el PSRepository y nunca publicar, podrías excluir el parámetro PublishLocation.

Publicando tu Módulo

Dado que ya configuraste la política de instalación como confiable, no recibirás una confirmación para permitir la instalación de un módulo desde el repositorio. Ahora que tienes un nuevo PSRepository disponible, puedes publicar tu módulo usando Publish-Module -Name .\Scripts\ATARegistry -Repository LocalRepo.

Después de publicar tu módulo, puedes usar los comandos anteriores para encontrar el módulo e instalarlo.

Ahora que has instalado el módulo, puedes usar Get-Module para ver el módulo importado en tu sesión local. Como no has agregado ninguna función al arreglo FunctionsToExport en el manifiesto, la propiedad ExportedCommands está vacía.

No exported commands

Agregar a tu módulo

Ahora que sabes que puedes publicar e instalar tu módulo, puedes comenzar a añadirle funcionalidad. Podrías agregar una función para devolver una clave de registro de la siguiente manera:

function Get-ATARegistryKey {
    param (
        [string]$Path
    )
    Get-Item $Path
}

Si dejaste el manifiesto como está e intentaste cargar tu nuevo módulo, te encontrarías con dos problemas. El primero es que recibirías un error que indica que la versión de tu módulo ya existe en tu repositorio. Esto se debe a que no has cambiado la versión del módulo en el archivo de manifiesto.

Exportando las funciones del módulo

El otro problema sería que después de importar el módulo, aún no verías ninguna función en la propiedad ExportedCommands porque no has agregado tu nueva función al manifiesto.

Aunque tu función se podría usar sin listarla en la lista FunctionsToExport, sería mucho más difícil de localizar.

Mientras no definas un array vacío, @(), para tus FunctionsToExport, todas las funciones, variables y alias se exportan automáticamente.

Para solucionar estos dos problemas, puedes actualizar tu archivo de módulo de esta manera:

ModuleVersion = '1.1'
FunctionsToExport = 'Get-RegistryKey'

Ahora que has agregado una función a tu módulo y has actualizado tu manifiesto para reflejar estos cambios, puedes publicar la nueva versión de tu módulo usando el mismo comando que antes.

PS51> Publish-Module -Name .\Scripts\ATARegistry -Repository LocalRepo.

Decidiendo Entre FunctionsToExport y Export-ModuleMember

Existen dos características similares en PowerShell al exportar miembros de módulos. El desafío está en decidir entre las dos. Ambas son correctas, pero una puede funcionar mejor para ti, dependiendo de tus necesidades.

Cuando deseas controlar dinámicamente qué funciones se exportan, utiliza Export-ModuleMember ya que puedes pasar una lista de funciones para exportar. Típicamente, esto se usa al cargar varios archivos de función PS1 individuales mediante dot-sourcing. Dividiendo las funciones internas en una carpeta privada y las funciones exportables en una carpeta pública, puedes exportar fácilmente aquellas pasando todas las funciones públicas a la función Export-ModuleMember.

A few notes about Export-ModuleMember:

  • Sobrescribe el comportamiento de FunctionsToExport, por lo tanto, si se usa un comando Export-ModuleMember, FunctionsToExport no tiene efecto.
  • Export-ModuleMember no exporta variables y alias sin definirlos explícitamente, a diferencia de FunctionsToExport, que sí exporta esos valores.
  • Se pueden usar múltiples comandos Export-ModuleMember y se apilan en lugar de tener precedencia.

Si no esperas tener cambios en tu lista de funciones, usar la configuración FunctionsToExport en el manifiesto del módulo funciona bien y no requiere que exportes explícitamente variables y alias.

Actualizando tu Módulo

El último paso sería que actualices tu módulo en tu sesión para poder usar los archivos actualizados. Usando Update-Module ATARegistry descargas la actualización que acabas de publicar en el repositorio.

Exported commands now show up

Ahora puedes ver que tienes la nueva versión del módulo y puedes ver la función que has definido en el manifiesto.

Construyendo Contenido de Ayuda

Una de las opciones que se pasó por alto anteriormente es el sistema de ayuda que está integrado en PowerShell. En algún momento probablemente hayas usado Get-Help en una función. Esta información se puede agregar de dos maneras principales.

La primera es agregar ayuda basada en comentarios en la definición de la función. Esta suele ser la forma en que muchos escritores de módulos la implementan. La otra manera es usar un archivo de ayuda externo. Puedes usar el parámetro Full para mostrar todo lo que la ayuda tiene para ofrecer.

Finding help with Get-Help

Como puedes ver, realmente no hay mucha información y la poca información que obtienes probablemente no sería útil para nadie.

Puedes agregar ayuda basada en comentarios a tu archivo de módulo para llenar estos campos en el sistema de ayuda. Puedes leer sobre todas las opciones para la ayuda basada en comentarios usando Get-Help about_Comment_Based_Help.

Por ahora, puedes actualizar tu función para que se vea así. Esta es una lista de los parámetros de ayuda más comúnmente utilizados, pero todos son opcionales y hay otros que se podrían agregar en su lugar.

Ahora tu función se ve así:

 function Get-RegistryKey {
	<#
	    .SINOPSIS
	    Devuelve la clave del registro utilizando la ruta proporcionada.
	    .DESCRIPCIÓN
	    La función utiliza el comando Get-Item para devolver la información de una clave de registro proporcionada.
	    .PARÁMETRO Ruta
	    La ruta que se buscará para una clave de registro.
	    .EJEMPLO
	    Get-RegistryKey -Path 'HKLM:\HARDWARE\DESCRIPTION\System'
	    .ENTRADAS
	    System.String
	    .SALIDAS
	    Microsoft.Win32.RegistryKey
	    .NOTAS
	    Este módulo es un ejemplo de cómo podría verse una función bien documentada.
	    .VÍNCULO
	
ATA Learning
#>
param( [string]$Path ) Get-Item $Path }

Existen algunos parámetros de ayuda especiales, como .FORWARDHELPTARGETNAME. Esta opción reenvía todas las solicitudes de ayuda entrantes a un comando diferente. Esto podría usarse en un caso donde la ayuda debería mostrar la misma información para varios comandos.

Ahora que has añadido la ayuda, puedes actualizar la versión en el manifiesto del módulo, publicar la nueva versión y actualizar la versión instalada para tu sesión, como hiciste anteriormente.

Si ahora miras la ayuda de la función, verás que hay mucha más información disponible. Esta es una excelente manera de incluir documentación sobre cómo usar las funciones, especialmente para alguien que tiene menos experiencia y puede que no pueda entender rápidamente lo que el módulo está haciendo al mirar el código.

Getting full help content with Get-Help

En el caso de un archivo de ayuda externa, la información adicional es la misma, pero se coloca en un archivo separado y se vincula dentro de la función.

Si miras en la ruta del módulo AllUsers, puedes ver la versión del módulo y todos los archivos del módulo que has estado instalando.

Folder name is the module version

Si vuelves a tu ruta de PSRepository C:\Repo que creaste anteriormente, puedes ver un montón de archivos NUPKG. Habrá uno para cada versión que se haya publicado. Estos son versiones comprimidas de lo que publicaste al usar Publish-Module.

Resumen

Una vez que tengas control sobre la consola de PowerShell, PowerShell como lenguaje y la escritura de scripts, construir tus propios módulos es el último paso. Los módulos te permiten comenzar a desarrollar herramientas útiles en PowerShell. Si están diseñados y construidos correctamente, creando módulos para un solo propósito, inevitablemente te encontrarás escribiendo menos y menos código con el tiempo. Comenzarás a hacer referencia a las funciones de tu módulo en más código y construir a partir de ahí.

Las funciones del módulo te permiten abstraer el código que te encuentras repitiendo en scripts. Representan “etiquetas” para referenciar más adelante en el código que se pueden llamar en cualquier momento en lugar de reinventar la rueda y tratar de averiguar cómo ya habías logrado tu objetivo anteriormente. Los módulos son la “empaquetadura” final del código de PowerShell que agrupa código afín para evitar perder tiempo en problemas que ya has resuelto.

Source:
https://adamtheautomator.com/powershell-modules/