Windows PowerShellAplicación de filtros y formato a los datos

Don Jones

No hay duda de que Windows PowerShell puede devolver gran cantidad de información valiosa sin que el usuario deba realizar un gran esfuerzo. Por ejemplo, observemos el sencillo cmdlet Get-WMIObject, que se puede usar para devolver una lista de servicios del equipo local. La vista predeterminada, que incluye en una lista el estado, el nombre y el modo de inicio de

los servicios en ejecución, es esencialmente una vista de línea de comandos de la consola Servicios. Windows PowerShell™ facilita enormemente el acceso.

Pero hay mucha más información útil disponible para los servicios, además de lo que se muestra en la vista predeterminada. Intente ejecutar este comando:

$s = get-wmiobject win32_service
$s[0] | gm

La primera línea del comando devuelve una colección de todos los servicios (o, más concretamente, de todas instancias de la clase Win32_Service del Instrumental de administración de Windows®, o WMI) y los almacena en la variable $s. La segunda línea toma el primer servicio de esa colección (el número ordinal cero, indicado entre corchetes) y lo canaliza al cmdlet Get-Mem­ber, que he abreviado con su alias, gm. La salida resultante muestra todas las propiedades y métodos disponibles para ese tipo de datos. He decidido usar la clase Win32_Service en WMI en lugar del cmdlet integrado Get-Service de Windows PowerShell porque WMI expone más información que el objeto Service-Controller de Microsoft® .NET, incluida la propiedad Start-Name. Esa propiedad me indica el nombre de la cuenta de usuario con la que se ejecuta el servicio. Puede comprobar el nombre de una única instancia, como, por ejemplo, la primera, de la siguiente manera:

PS C:\> $s[0].StartName
LocalSystem

Sin embargo, la referencia a servicios por su número ordinal dentro de la colección no es muy útil, puesto que los servicios no están en ningún orden concreto. (Normalmente, aparecen en orden alfabético, pero no siempre). Desde una perspectiva de administración, es muy probable que lo que más le interese es obtener una lista de todos los servicios y la cuenta que usa cada uno de ellos para iniciar sesión. Esto sería útil, por ejemplo, para una auditoría de cumplimiento. Retrocedamos un momento y observemos los datos que WMI proporciona de forma predeterminada. Usaré el alias más corto de Get-WMIObject, gwmi (consulte la Figura 1).

Figure 1 Uso de gwmi

PS C:\> gwmi win32_service

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

ExitCode  : 1077
Name      : Adobe LM Service
ProcessId : 0
StartMode : Manual
State     : Stopped
Status    : OK

Obviamente, esto sólo es un ejemplo, pero puede observar que la salida no demasiado útil para un informe de administración. Lo que deseo conocer es el nombre del servicio y la propiedad StartName, que es la cuenta con la que se ejecuta el servicio. También me gustaría que el informe tuviera un formato más legible, en lugar de esta lista, que tiene un aspecto un tanto raro. Aquí es donde entran en acción los formidables cmdlets para filtrar datos y aplicar formato de Windows PowerShell.

Obtenga los datos que necesita

Empezaré por filtrar los datos de Get-WMIObject con el fin de mostrar las propiedades que me interesan. La mejor manera de hacerlo es usar el cmdlet Select-Object de Windows PowerShell o su alias sencillo, select. Select está diseñado para aceptar una colección de objetos (como, por ejemplo, la colección devuelta por Get-WMIObject) y mostrar sólo las propiedades deseadas de esos objetos. Esto significa que puedo canalizar la salida de gwmi para seleccionar y especificar las dos propiedades que me interesan. La Figura 2 muestra los resultados, que incluyen las propiedades Name y StartName con un formato agradable de tabla.

Figura 2 Ver únicamente las propiedades Name y StartName en una tabla

Figura 2** Ver únicamente las propiedades Name y StartName en una tabla **(Hacer clic en la imagen para ampliarla)

No obstante, si tuviera que crear este informe para una auditoría de cumplimiento, contendría demasiada información. Algunos de los servicios están deshabilitados, de modo que es muy probable que las personas que lean el informe no estén nada interesadas en saber cuál es la cuenta que usarían teóricamente los servicios deshabilitados. Por tanto, me gustaría quitar de la lista mediante un filtro todos los servicios que tienen un tipo de inicio Disabled (en la propiedad StartMode de la clase Win32_Service).

Windows PowerShell filtra los objetos con el cmdlet Where-Object o su alias más corto, where. El cmdlet where acepta una colección de objetos de entrada y los pasa a través de un bloque Script para determinar si cada uno de ellos estará presente en la salida del cmdlet según un conjunto de criterios definidos. Cada objeto que cumple los criterios produce una comparación verdadera (True) y se incluye en la salida; los objetos que producen un valor falso (False) no se incluyen.

De esta forma, he determinado que sólo deseo obtener los objetos cuya propiedad StartMode sea igual a Disabled. En términos de Windows PowerShell, esta evaluación tiene el siguiente aspecto:

$object.StartMode –eq “Disabled”

Por supuesto, $object es únicamente un ejemplo. No estoy escribiendo un script real, por lo que no tengo una variable denominada $object. En el bloque Script usado por where, no obstante, sí que se usa una variable especial denominada $_, que representa el objeto que evalúa actualmente el cmdlet. Así, el bloque script de where que he creado puede tener el siguiente aspecto:

$_.StartMode –eq “Disabled”

Se puede probar fácilmente:

PS C:\> gwmi win32_service | where 
{$_.StartMode -eq “Disabled”}

ExitCode  : 1077
Name      : Alerter
ProcessId : 0
StartMode : Disabled
State     : Stopped
Status    : OK

Por supuesto, en esta prueba rápida, la salida vuelve a aparecer con el estilo de lista predeterminado. Además, para ahorrar espacio, sólo he incluido un servicio. Pero advertirá que esta salida tiene un orden inverso. He incluido los servicios deshabilitados, en lugar de excluirlos. El motivo es que el bloque Script va hacia atrás: Necesito incluir todos servicios donde StartMode no sea igual a Disabled, tal como muestra esta modificación de mi ejemplo:

PS C:\> gwmi win32_service | where 
{$_.StartMode -ne “Disabled”}

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

Eso está mejor. Ahora que la salida contiene sólo los servicios que me interesan realmente, puedo canalizar de nuevo la salida para seleccionar y especificar únicamente las propiedades que deseo:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | select name,startname

La canalización de datos un cmdlet a otro y a otro más ilustra las capacidades de Windows PowerShell. Todavía no he escrito ningún script, pero he conseguido filtrar un gran conjunto de datos para obtener la salida que deseo.

El aspecto correcto

Debe tener presente que la salida de select sigue siendo un montón de objetos. Al recuperar una tabla con formato agradable mediante Windows PowerShell, esta tabla es realmente la representación de PowerShell.exe de esos objetos. Es decir, Windows PowerShell sabe que yo, como mero ser humano, no puedo ver los objetos, de modo que los representa como texto. En este caso, he representado los objetos como una tabla, con una columna para cara propiedad, como se ilustra en la Figura 2.

Quizás esto sea suficiente para la auditoría que tengo que realizar. Pero quizás no lo sea. Todas las personas tienen necesidades distintas y Windows PowerShell no pretende saber cuáles son sus necesidades específicas. En su lugar, le proporciona las herramientas que necesita para aplicar formato a la salida de la forma que se ajuste mejor a sus necesidades. Cuatro cmdlets integrados (Format-List, Format-Custom, Format-Table y Format-Wide) están diseñados para aceptar una colección de objetos (como, por ejemplo, la colección devuelta por select) y aplicar formato a esos objetos de varias maneras. Format-Table es básicamente lo que Windows PowerShell ya usa para aplicar formato la salida de mi cmdlet select. Para un aspecto diferente, probemos Format-List:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | format-list

El resultado tiene un aspecto parecido a este ejemplo:

name      : AcrSch2Svc
startname : LocalSystem

name      : Adobe LM Service
startname : LocalSystem

El cmdlet Format-Wide está diseñado para producir de forma predeterminada una lista con varias columnas de la primera propiedad de cada objeto. Veamos esta línea, por ejemplo:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} |
 select name,startname | format-wide

Produce una lista de nombres de servicio, que no es lo que deseo obtener. En la salida falta StartName (consulte la Figura 3), que es un dato importante que necesito en mi informe de auditoría.

Figura 3 La salida mostrada con el cmdlet Format-Wide omite información clave: la propiedad StartName

Figura 3** La salida mostrada con el cmdlet Format-Wide omite información clave: la propiedad StartName **(Hacer clic en la imagen para ampliarla)

Como sólo trabajo con dos propiedades, es probable que Format-Table o Format-List sean aceptables. Pero es improbable que a un auditor le gustara ver esta información en pantalla. Probablemente preferiría tener algún tipo de archivo.

Exportación de los datos

Así, pues, ¿cómo podría desear ver un auditor los datos? La inclusión de la lista de servicios y nombres de inicio de sesión en un archivo CSV (valores separados por comas) podría resultar suficiente, puesto que el archivo se puede abrir fácilmente en Microsoft Excel®. Para crear un archivo CSV sólo hay que canalizar la salida al cmdlet Export-CSV de Windows PowerShell:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | export-csv c:\services.csv

Por supuesto, en el mundo actual, el formato CSV parece un poco anticuado. Quizás sus auditores preferirían que los datos se mostraran como páginas web en un servidor de la intranet. Para ello, convierta la salida a HTML con el cmdlet ConvertTo-HTML:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html

El código HTML sin procesar es difícil de ver, por lo que deberá escribir la salida en un archivo:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html | out-file c:\services.html

El resultado, mostrado en la Figura 4, es una página HTML con formato correcto que se puede publicar en cualquier servidor web sin modificaciones adicionales.

Figura 4 Salida mostrada como página HTML con formato correcto

Figura 4** Salida mostrada como página HTML con formato correcto **(Hacer clic en la imagen para ampliarla)

Sólo los datos (pertinentes)

Windows PowerShell le ofrece acceso rápido a un amplio espectro de datos de administración. Sin embargo, esos datos sin procesar no siempre son útiles en un sentido de negocio.

Si filtra los datos (con where), elige las propiedades de objeto deseadas (con select) y aplica una opción de formato apropiada (como, por ejemplo, Format-Table o Format-List), podrá convertir rápidamente estos datos de administración en información útil con muy poco esfuerzo. Y, a continuación, si exporta los datos a un formato de archivo que se pueda compartir fácilmente, podrá trasladar esta información más allá de su propio escritorio y comunicar información valiosa a otras personas de su organización.

Don Jones es el director de proyectos y servicios de SAPIEN Technologies y coautor de Windows PowerShell: TFM (SAPIEN Press). Póngase en contacto con Don a través de su sitio web en www.ScriptingAnswers.com (en inglés).

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