Windows PowerShellAspectos positivos

Don Jones

Muchas veces es deseable que los scripts produzcan resultados con un buen aspecto y con frecuencia la gente me pregunta cuál es la mejor manera de crear elementos como, por ejemplo, tablas. En realidad, hay dos maneras de hacerlo. El primer paso es escribir un script que coloca los datos (es decir, los datos que deseo mostrar con formato) en variables denominadas

$data1, $data2 y $data3. Ahora puedo proceder a dar formato a los datos.

La vía de texto

En la Web

¿Busca una demostración rápida de las técnicas tratadas en la columna de Windows PowerShell de este mes? Vaya a technetmagazine.com/video para ver cómo Don Jones pone en acción estos cmdlets.

La metodología más común que la gente suele usar para abordar esta tarea es igual a la que aplicaría cuando trabaja con lenguajes tales como VBScript, Perl, KiXtart u otro lenguaje orientado al texto. Podría comenzar por escribir un conjunto de encabezados de columna en la pantalla:

Write-Host "ColumnA'tColumnB'tColumnC"

Tenga en cuenta que `t es una secuencia de escape especial en Windows PowerShellTM que inserta un carácter de tabulación. Para escribir cada línea de mi tabla, recordando que mis datos están en $data1, $data2 y $data3, tengo varias opciones. Una es escribir simplemente las variables y depender de la capacidad del shell para reemplazar las variables con su contenido entre comillas dobles:

Write-Host "$data1't$data2't$data3"

Otra un manera algo más atractiva para lograr esto usa el operador -f. Esta técnica separa el formato de los datos y crea una línea de código que, en mi opinión, es más fácil leer y mantener:

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

Sin embargo, este método presenta importantes problemas. En primer lugar, al depender de saltos de tabulación fijos en la ventana de consola, estoy preparando el terreno para un formato inusual. Por ejemplo, si una fila en particular de la tabla tiene un valor de 20 caracteres en la primera columna, todo el formato quedará desequilibrado. Además, dato que produzco este texto mediante Write-Host, estoy limitado a una pantalla de consola.

No hay una manera fácil de enviar los resultados a un archivo ni de colocarlos en otros formatos, si lo deseara. Lo más importante, este enfoque basado en texto no toma en cuenta el shell intrínsecamente basado en objetos con el que trabajo, de modo que no se saca partido de las increíbles técnicas y capacidades que ofrece Windows PowerShell.

El método de Windows PowerShell

Windows PowerShell es un shell orientado a objetos. Idealmente, esto significa que todos los elementos con los que trabaje deben encontrarse en objetos, de modo que el shell podrá convertirlos en visualizaciones de texto cuando sea necesario. Pero, ¿cómo se crean objetos para fragmentos arbitrarios de datos?

Siguiendo mi ejemplo, comienzo con la creación de un objeto personalizado en blanco y su almacenamiento en una variable:

 $obj = New-Object PSObject

De este modo, dispongo de un nuevo objeto vacío con el que trabajar. A continuación, agrego los datos al objeto en forma de propiedades. Para ello, simplemente canalizo el objeto al cmdlet Add-Member. Agrego un elemento denominado NoteProperty, asigno un nombre a la propiedad (una idea buena es usar los encabezados de columna como nombres de propiedad) y, a continuación, inserto los datos como los valores para las propiedades:

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

Ahora, simplemente obtengo los resultados de objeto, no a la consola, pero a la canalización:

Write-Output $obj

A continuación, puedo repetir estos pasos para cada fila de tabla que necesito como resultado. A continuación se incluye una breve función que acepta una cadena y tiene como resultado una versión en mayúsculas y una en minúsculas, junto con la cadena original:

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

Comienzo con una matriz de variables de cadena, trabajo en cada una de ellas individualmente y las envío a la función. Y los resultados de la función se escriben en la canalización.

Debe tener en cuenta que hay las maneras más breves de escribir este código, pero elegí esta técnica porque muestra claramente lo que intento plantear. El resultado, tal como se muestra en la figura 1, es una tabla con formato correcto. Esto se debe a que el shell ya sabe cómo dar formato a los objetos de una tabla.

Figura 1 Resultados de Windows PowerShell mostrados en una tabla

Figura 1** Resultados de Windows PowerShell mostrados en una tabla **(Hacer clic en la imagen para ampliarla)

Siempre que un objeto tenga cuatro o menos propiedades, Windows PowerShell elige automáticamente una tabla. De este modo, sin haber hecho absolutamente nada, tengo una tabla con un gran aspecto.

Pero espere, hay mucho más.

Cmdlet del mes Get-Command

Estoy seguro que ha usado alguna vez Get-Command, o su útil alias (gcm), para revisar la lista de cmdlets de Windows PowerShell disponibles. Sin embargo, es posible que desconozca el grado de flexibilidad real de gcm. Por ejemplo si desea ver todo lo que puede hacer Windows PowerShell con un servicio, ejecute gcm -noun service. O bien, si desea ver todas las opciones de la exportación de Windows PowerShell, intente ejecutar gcm -verb export. Si simplemente necesita ver los cmdlets que ha agregado un complemento en particular, como por ejemplo, las extensiones de la comunidad de PowerShell, intente ejecutar gcm -pssnapin pscx (puede reemplazar "pscx" con cualquier nombre de complemento para consultar los cmdlets de ese complemento).

Como puede observar, Get-Command es elemento clave en la capacidad de detección de Windows PowerShell. Permite conocer la funcionalidad que está disponible sin tener que acudir a ningún manual. Además, tenga en cuenta que gcm es una manera más precisa de descubrir la funcionalidad que el uso de un comando tal como Help *. La función Help sólo incluye en una lista de los temas de ayuda disponibles. Los cmdlets no incluidos en ayuda no aparecen en el listado, incluso si se encuentran allí para cuando los necesite.

La ventaja de esta técnica va mucho más allá de las tablas. Al trabajar con objetos, Windows PowerShell sabe cómo hacer una amplia variedad de cosas. ¿Desea sus datos en un archivo CSV? Use Export-CSV. ¿Prefiere una tabla HTML? Cree una canalización de los objetos hacia ConvertTo-HTML. ¿Necesita un formato en lista? Cree una canalización de los objetos hacia Format-List. Mediante el uso de objetos, puede aprovechar todas las capacidades del shell. A continuación se incluye un ejemplo modificado:

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

Esta vez, modifiqué la función para aceptar entradas de canalización (siempre una mejor idea cuando se trabaja con objetos) y enviar los resultados a la canalización.

Esta función ahora tiene su código dentro de un bloque script PROCESS. Esto significa que la función aceptará entradas de canalización y ejecutará el bloque script PROCESS una vez para cada objeto que entra.

Dentro del bloque script PROCESS, la variable especial $_ hace referencia al objeto actual de canalización que se está procesando. El resultado práctico de esto es que ahora puedo canalizar una matriz de cadenas:

@("one","two","three") | StringVersions

Obtengo una tabla porque la función coloca sus resultados en la canalización. Al final de la canalización, el shell sabe que debe invocar su subsistema de formato, que toma la decisión de usar una tabla porque los objetos de la canalización tienen menos de cinco propiedades (si hay un mayor número de propiedades, el shell usará una lista de forma predeterminada).

Pero no hace falta depender del comportamiento predeterminado. Puedo simplemente canalizar esos objetos a otro cmdlet para pasarlos por un proceso adicional:

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

La figura 2 muestra el HTML resultante del segundo ejemplo mostrado en un explorador web. Al representar los datos de salida en objetos, en lugar de representarlos como texto sencillo, ahora dispongo de acceso completo a una amplia variedad de funciones integradas en el shell: una serie de diseños de formato, conversión HTML, opciones de exportación, capacidad de clasificar, filtrar y agrupar, y mucho más.

Figura 2 Resultados de datos de Windows PowerShell en formato HTML

Figura 2** Resultados de datos de Windows PowerShell en formato HTML **(Hacer clic en la imagen para ampliarla)

Todo esto es muy eficaz. De hecho, sugeriría que cada script que escriba debe producir un objeto como su resultado, de modo que podrá usar estos resultados la mayor cantidad de maneras diferentes posible, todo sin tener que escribir una sola línea adicional de código.

Don Jones es un experto en la automatización administrativa de Windows y ha escrito varios libros, tal como Windows PowerShell: TFM y VBScript, WMI, and ADSI Unleashed. Puede ponerse en contacto con él a través de los foros en ScriptingAnswers.com.

© 2008 Microsoft Corporation and CMP Media, LLC. Reservados todos los derechos. Queda prohibida la reproducción parcial o total sin previa autorización.