Windows PowerShell: Convierta un comando en una herramienta reutilizable

Puede volver a empaquetar y reutilizar sus esfuerzos cuando se trata de comandos y cmdlets de Windows PowerShell.

Don Jones

No importa cómo sin experiencia está con Windows PowerShell cuando primero comience a trabajar con él, siempre hay mucho espacio para el crecimiento. Puede empezar a ejecutar comandos simples, trabajar a los comandos más complicado y eventualmente volver a empaquetar los comandos en algo que se ve y se siente casi como un cmdlet nativo. Estos se denominan funciones avanzadas y se conocen informalmente como "cmdlets de secuencia de comandos".

Considere la posibilidad de una situación donde puede que desee recuperar cierta información de inventario crítico de un equipo. Necesita la versión de Windows, el número de serie del BIOS, la arquitectura de procesador y la versión del paquete de servicio. Puede obtener esta información con estos tres comandos:

Get-WmiObject –class Win32_OperatingSystem –computername SERVER-R2 | Select-Object –property __SERVER,BuildNumber,Caption,ServicePackMajorVersion
Get-WmiObject –class Win32_BIOS –computername SERVER-R2 | Select-Object –property SerialNumber
Get-WmiObject –class Win32_Processor –computername SERVER-R2 | Select-Object –property AddressWidth

El problema es que estos comandos generan tres conjuntos de resultados diferentes. Usted no puede directamente tubería todo lo que fuera a un único archivo CSV, por ejemplo, para almacenar los datos de inventario, o un solo archivo HTML para mostrar el inventario como una página Web. Es preferible agrupar los datos en un único comando con parámetros que aún podría usar un usuario con menos experiencia. Es necesario que el comando:

  • Aceptar uno o más nombres de equipo como cadenas de caracteres de la tubería, como en:
Get-Content names.txt | Get-OSInfo | ConvertTo-HTML | Out-File info.html
  • Aceptar uno o más nombres de equipo en un parámetro de –computername, como en:
Get-OSInfo –computername Server-R2,ServerDC4 | Format-Table
  • Aceptar de la canalización de uno o más objetos que cada uno tiene una propiedad de nombre del equipo, como en:
Get-ADComputer –filter * -searchbase "ou=West,dc=company,dc=com" | Select-Object @{label='computername';expression={_.Name}} | Get-OSInfo | Export-CSV inventory.csv

De esta forma, usted no necesitará preocuparse acerca de donde provienen los nombres de equipo. También nunca necesitan preocuparse de qué tipo de salida le creará. Va a controlar el shell.

Además, querrá tener un parámetro de –logfile, que aceptará una ruta y un nombre de archivo de un archivo de registro. Debido a que el comando todavía utiliza Windows Management Instrumentation (WMI) para conectarse y consultar información, existe la posibilidad de que no podrá llegar a uno o más equipos. Hay que tener sus nombres escritos en el archivo de registro, que posteriormente se puede utilizar para solucionar el problema o incluso para volver a intentar esos equipos.

Tratar con errores

Se puede lograr ese último bit utilizando el Try…Construcción de capturas PowerShell. Simplemente ajustar la primera consulta WMI en un Try…Captura de bloque. A continuación, especifique el parámetro de la parada de –ErrorAction, por lo que será capaz de atrapar los errores que genera el comando. Establecer una variable que realiza un seguimiento de si se ha producido un error, por lo que la secuencia de comandos de saber si se va a tratar de las siguientes dos consultas WMI:

continue = True
Try {
  Get-WmiObject –class Win32_BIOS –computername computername –EA Stop
} Catch {
  continue = False
  computername | Out-File –path logfile –append
}

Tratar de entrada

La parte difícil se ocupa de la entrada. Recibirá la entrada de una de dos maneras: a través de la tubería o a través de un parámetro. Realmente puede dirigir entrada llegando a través de la tubería para el parámetro, mediante el enlace de parámetro de estilo cmdlet. Esta es la estructura básica de:

Function Get-OSInfo {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=True,ValueFromPipeline=True,ValueFromPipelineByPropertyName=True)]
  [string[]]computername,
  [string]logfile 
 )
  BEGIN {}
  PROCESS {}
  END {}
}

El bloque de proceso dentro del cmdlet está garantizado para ejecutar al menos una vez, que lo hará si no hay ninguna entrada de tubería proporcionada. Si hay aportaciones de tubería, a continuación, el bloque de proceso se ejecutará una vez para cada elemento por departamento en. Colocará ese elemento en la variable de nombreDeEquipo.

Ahí reside el problema: Si sólo se especifica la entrada a través de un parámetro, como en el segundo ejemplo con viñetas, a continuación, proceso sólo ejecutará una vez. El nombre del equipo contendrá cada nombre de equipo que se dio al parámetro. Tendría que enumerar o "relajarse" esos usted mismo. Si esos elementos son canalizados en, a continuación, sólo tendrá que trabajar con un elemento a la vez. Usted obtendrá todavía en la variable de nombreDeEquipo.

El truco consiste en crear una segunda función que realiza el trabajo real. Utilice la función avanzada para aceptar cualquier tipo de entrada y rompen cosas en nombre de un equipo a la vez. A continuación, llamar a la función de "trabajador" segunda con un nombre de equipo único en un momento. Aquí está la estructura básica, que iría dentro del bloque de proceso de la función principal:

PROCESS {
  if (PSBoundParameters.ContainsKey('computername')) {
    foreach(computer in computername) {
      OSInfoWorker –computername computer –logfile logfile
    }
  } else {
    OSInfoWorker –computername computername –logfile logfile
  }
}

Terminar

Con los importantes obstáculos técnicos resueltos, ponerlo todo junto y agregar algunos otros detalles, tales como limpiar archivos de registro antiguos antes de ejecutar la función cada vez (que es un candidato perfecto para el bloque BEGIN). La secuencia de comandos resultante, que consiste en dos funciones, es un poco larga. Sin embargo, muy poco de ella es real "programación". La mayor parte es sólo Windows PowerShell comandos, como se ejecuta en la línea de comandos. Sólo está rodeados de una gran estructura declarativa hacer que todo se comportan como un cmdlet.

Toda la cosa está publicada en mi sitio Web en ow.ly/39YcX , junto con un tutorial de vídeo sobre el código final. Se trata de una plantilla que se puede reutilizar absolutamente. La función principal realmente sólo está enfrentando la entrada, para que pueda utilizar casi como es. Cambiar los parámetros para que coincidan con sus necesidades específicas, y eso es bueno para ir. El trabajo real que se está haciendo en una función separada.

El próximo mes, les mostraré cómo empaquetar todo esto como un módulo de secuencia de comandos de fácil de distribuir. También le mostraré cómo configurar una ubicación compartida para los módulos de secuencia de comandos que pueden utilizar todos sus colegas de administrador.

Don Jones

Don Jones es uno de los fundadores de la tecnología de concentrado y preguntas de respuestas acerca de Windows PowerShell y otras tecnologías en ConcentratedTech.com. También es un autor de Nexus.Realtimepublishers.com, que hace que muchos de sus libros disponibles como libres ediciones electrónicas a través de su sitio web.

 

Obtenga más

Artículo de este mes tiene un tutorial de vídeo de compañero, así como código de ejemplo descargable. Obtener estos extras aquí.

Contenido relacionado