Los Módulos En Windows PowerShell v2.0

Los módulos

Una muy interesante novedad que incorpora Powershell V 2.0 son los módulos. Los módulos permiten a los desarrolladores y administradores dividir y organizar el código en unidades autocontenidas y reutilizables. El código proveniente de un módulo se ejecuta en un contexto que está contenido en el propio módulo y no afecta a lo que está fuera; dicho de una forma más fácil: permite definir variables, alias, funciones, etc., de forma privada o pública (que se puedan invocar sólo desde el propio módulo, privadas, o directamente desde la línea de comandos o un script de Powershell, públicas, una vez se ha importado el módulo. Esto significa que podemos crear un script y que éste se ejecute en un espacio de trabajo restringido.

Pongamos un ejemplo. Vamos a construir un módulo que se base en un script de Powershell y que nos muestre los discos lógicos de una lista de equipos recibida como parámetro en forma de array de cadenas. Al objeto de tipo Win32_LogicalDisk le agregaremos dos propiedades, una que es la explicación en texto de su propiedad DriveType, que es una enumeración, y la segunda propiedad es el espacio ocupado, obtenido al restar el espacio libre del espacio total. Veamos este script:

# Declaramos un parámetro de entrada de tipo array de cadenas, cuyo valor en
# caso de ser omitido es ".": equipo local
param([String[]]$Equipos = ".")
Function f_Ocupacion($Disco)
# Esta función recibe un objeto Win32_LogicalDisk y devuelve su espacio ocupado
{
    Return $Disco.Size - $Disco.FreeSpace
}
Function f_Tipo($Disco)
# Esta función recibe un objeto Win32_LogicalDisk y devuelve como cadena el
# valor numérico que identifica el tipo de disco que es
{
    Switch($Disco.DriveType)
    {
        0 {"Unknown"}
        1 {"No Root Directory"}
        2 {"Removable Disk"}
        3 {"Local Disk"}
        4 {"Network Drive"}
        5 {"Compact Disc"}
        6 {"RAM Disk"}
    }
}

Function Get-LogicalDisk($Equipos)
# Esta función recibe una lista de equipos y devuelve los discos lógicos de los
# mismos, agregando dos propiedades: Type, que es la traducción a cadena de la
# propiedad numérica DriveType y OccupiedSpace que es el espacio en disco que está
# ocupado
{
    ForEach($Equipo In $Equipos)
    {
        $wmi_Discos = Get-WmiObject Win32_LogicalDisk
        ForEach($wmi_Disco In $wmi_Discos)
        {
        $wmi_Disco|Add-Member NoteProperty Type          $(f_Tipo $wmi_Disco)
        $wmi_Disco|Add-Member NoteProperty OccupiedSpace $(f_Ocupacion $wmi_Disco)
        $wmi_Disco
        }
    }
}
# Hacemos visible desde el exterior del módulo tan sólo la función Get-LogicalDisk;
# las otras dos (f_Tipo y f_Ocupado) sólo se podrán llamar desde dentro del módulo
Export-ModuleMember Get-LogicalDisk

Este script lo debemos guardar no como *.ps1, si no como *.psm1. Por ejemplo lo llamaremos LogicalDisk.psm1. Para que este módulo sea cargado (y por tanto que podamos ejecutar Get-LogicalDisk como otro Cmdlet más de Powershell) debemos usar Import-Module:

PS> Import-Module LogicalDisk

Aparentemente no habrá pasado nada, pero si ejecutamos Get-LogicalDisk veremos que funciona.

En el ejemplo de importación se ve que no hemos puesto la ruta y nombre del fichero *.psm1 ¿por qué? Bueno, los módulos se pueden importar cuando están en cualquier ubicación si se pone su ruta y nombre; sin embargo, si los ubicamos contenidos en una carpeta con su propio nombre sin la extensión (en el ejemplo lo guardaríamos en una carpeta de nombre LogicalDisk) y ésta carpeta la situamos en una de las dos rutas predeterminadas, podremos importar el módulo como hemos visto antes, tan solo con poner su nombre. He hablado de dos rutas predeterminadas ¿Cuáles son? Ejecutemos desde Powershell:

PS> $env:PSModulePath
C:\Users\Mortadelo\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

Este comando nos devuelve un valor de Path con dos rutas: una es la de usuario y está en su perfil (los módulos ahí contenidos sólo podrán ser cargados por el usuario dueño del perfil), en %UserProfile%\Documents\WindowsPowershell\Modules y la otra es la de equipo y puede ser utilizada por todos los usuarios del equipo; su ruta es %WinDir%\System32\WindowsPowershell\v1.0\Modules. Esto no es inamovible, pues podemos agregar más rutas a PSModulePath o incluso cambiar por completo el valor de esta variable de entorno. En este ejemplo supondremos que tenemos una carpeta c:\WindowsPowershell\Modules y la agregamos al Path:

PS> $env:PSModulePath = $env:PSModulePath + ";C:\WindowsPowershell\Modules"
PS> $env:PSModulePath
C:\Users\Mortadelo\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\;C:\WindowsP
owershell\Modules

Una vez agregada esa ruta al Path, podremos importar los módulos que estén en esa carpeta contenidos con solo poner los nombres de las carpetas que los contienen.

Si nos fijamos, este proceder de Powershell con los módulos indica una cosa muy interesante: cualquier usuario, independientemente del nivel de privilegios, podrá cargar módulos para así personalizar su consola, tan solo con tener acceso a la carpeta donde estos módulos estén. Hasta ahora era necesario hacer instalaciones que requerían provilegios de administrador para obtener esto mismo; ahora sólo es necesario tener una carpeta accesible para un usuario normal para que éste los agregue a su consola.

No es necesario que la carpeta de los módulos se incluya en la variable de entorno PSModulePath pues pueden ser importados desde cualquier ubicación pasándo la ruta completa al módulo:

PS> Import-Module c:\PowerShell\Modulos\ObtenerDiscoLogico\ObtenerDiscoLogico.psm1

No obstante, no es esta una práctica recomendable, es preferible tener localizados los módulos en rutas concretas y que se puedan cargar sin más.

No sólo se pueden especificar scripts de Powershell como módulos; los posibles orígenes son dos:

Los manifiestos

Los módulos pueden ser acompañados de un manifiesto, un fichero de datos de PowerShell (.psd1), que nos permite:

Los manifiestos no son requeridos por los módulos.

Los manifiestos pueden referenciar scripts (*.ps1), ficheros de módulos (*.psm1), otros ficheros de manifiesto (*.psd1), ficheros de formatos y tipos (*.ps1xml), ensamblados con proveedores y Cmdlets (*.dll), ficheros de recursos, ficheros de ayuda, referencias de localizaciones de ficheros y cualquier otro tipo de archivo o recurso que sea incluído como parte del módulo. Incluso se puede incluir un catálogo de ficheros de mensajes para el caso de hacer un módulo con multilenguaje. El uso de un manifiesto en la carpeta de un módulo permite poder referenciar todos estos ficheros como un simple unidad.

Los tipos de información de un manifiesto son:

Un módulo es una tabla hash, cuyas palabras clave son:

El Cmdlet New-ModuleManifest nos permite crear el fichero de manifiesto de forma interactiva, preguntandonos los diferentes parámetros requeridos por el mismo y generando un fichero de manifiesto que podemos usar luego como plantilla. Por ejemplo, si ejecutamos esto desde una consola de PowerShell:

PS D:\Perfiles\ReyesF2> New-ModuleManifest

cmdlet New-ModuleManifest en la posición 1 de la canalización de comandos
Proporcione valores para los parámetros siguientes:
Path: .\DesfibriladorNeuroIronico.psd1
NestedModules[0]:
Author: Profesor Bacterio
CompanyName: TIA
Copyright: TIA © 2010
ModuleToProcess: DesfibriladorNeuroironico.psm1
Description: Funciones que permiten gestionar el tremendo arma Desfibrilador Neuro-Irónico, de dudoso funcionamiento.
TypesToProcess[0]:
FormatsToProcess[0]:
RequiredAssemblies[0]:
FileList[0]: DesfibriladorNeuroIronico.psm1
FileList[1]:

Esto nos da como resultado un fichero con el siguiente contenido:

#
# Manifiesto del módulo 'DesfibriladorNeuroIronico'
#
# Generado por Profesor Bacterio
#
# Generado el 14/10/2010
#

@{

# Módulo de script o archivo de módulo binario asociado con este manifiesto.
ModuleToProcess = 'DesfibriladorNeuroironico.psm1'

# Número de versión de este módulo.
ModuleVersion = '1.0'

# Id. usado para identificar de forma única este módulo.
GUID = 'f65c91da-7062-4b87-aa17-9f27b83c104a'

# Autor de este módulo.
Author = 'Profesor Bacterio'

# Compańía o proveedor de este módulo.
CompanyName = 'TIA'

# Instrucción de copyright de este módulo.
Copyright = 'TIA © 2010'

# Descripción de la funcionalidad proporcionada por este módulo.
Description = 'Funciones que permiten gestionar el tremendo arma Desfibrilador Neuro-Irónico, de dudoso funcionamiento.'

# Versión mínima del motor de Windows PowerShell requerida por este módulo.
PowerShellVersion = ''

# El 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 .NET Framework requerida por este módulo.
DotNetFrameworkVersion = ''

# Versión mínima de Common Language Runtime (CLR) requerida por este módulo.
CLRVersion = ''

# Arquitectura de procesador (None, X86, Amd64 o IA64) que requiere este módulo.
ProcessorArchitecture = ''

# Módulos que se deben importar en el entorno global antes de importar este módulo.
RequiredModules = @()

# Ensamblados que se deben cargar 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 van a cargar al importar este módulo.
TypesToProcess = @()

# Archivos de formato (.ps1xml) que se van a cargar al importar este módulo.
FormatsToProcess = @()

# Módulos para importar como módulos anidados del módulo especificado en ModuleToProcess.
NestedModules = @()

# Funciones para exportar desde este módulo.
FunctionsToExport = '*'

# Cmdlets para exportar desde este módulo.
CmdletsToExport = '*'

# Variables para exportar desde este módulo.
VariablesToExport = '*'

# Alias para exportar desde este módulo.
AliasesToExport = '*'

# Lista de todos los módulos empaquetados con este módulo.
ModuleList = @()

# Lista de todos los paquetes con este módulo.
FileList = 'DesfibriladorNeuroIronico.psm1'

# Datos privados para pasar al módulo especificado en ModuleToProcess.
PrivateData = ''

}

Este fichero lo podemos editar a nuestra conveniencia para ajustarlo a las necesidades que tengamos.

Cmdlets y variables referentes a los módulos

He aquí los nuevos Cmdlets para el trabajo con módulos:

Hay dos nuevas variables referentes a los módulos:

¿Qué todavía sigues usando tu viejo PowerShell 1.0? ¡¡Arrepiéntete, finstro de pecadorl, y bájate la versión 2.0 desde aquí!!