Windows PowerShellTeoría de cadenas

Don Jones

Contenido

Un caso real
Coincidencias complejas
El mundo está lleno de cadenas

Cuando hablo en las conferencias, como en Tech•Ed o TechMentor, tengo tendencia a hacer proclamas, anuncios de reglas generales que ayudan a los usuarios a recordar puntos clave acerca de cosas como Windows PowerShell. Mi última proclama es ésta: "Si tiene que analizar una cadena en Windows PowerShell, es que está haciendo algo mal".

Esto proviene de mi filosofía respecto a que Windows PowerShell™ es un shell orientado a objetos. Si está haciendo cosas como volcar listas de servicios en un archivo de texto y después analizar ese archivo de texto para consultar los servicios que se han iniciado, se está esforzando demasiado. Se trata de un enfoque válido en un sistema operativo basado en texto como Unix, pero Windows PowerShell (así como el propio Windows®) permite usar objetos de forma mucho más eficaz.

Incluso en sus propios scripts deberían producir objetos y no texto con formato, para que los distintos comandos de formato, filtrado, exportación, etc. de shell se puedan usar para manipular la salida de sus scripts. (En mi artículo de Windows PowerShell de julio de 2008 puede leer más acerca del concepto de objetos personalizados como salida de scripts).

En un TechMentor reciente en Orlando, Florida, uno de mis estudiantes me recordó que casi todas las reglas, especialmente las generales, tienen excepciones. "¿Y cuando se tienen que encontrar cosas en un archivo de registro de IIS? ¿En ese caso no hace falta analizar el texto necesariamente?"

Bien, en ese caso... sí. Y, afortunadamente, a pesar de lo bien que maneja los objetos Windows PowerShell, tampoco se queda atrás cuando se trata de analizar sintácticamente cadenas de texto. Y ahora que lo menciona, los archivos de registro de IIS, los archivos de registro del firewall y otros registros basados en texto son ejemplos perfectos.

Un caso real

Tuve que analizar un conjunto de archivos de registro de firewall para una compañía para la que estaba trabajando. Se había sorprendido a un empleado viendo algunos sitios web poco adecuados y como parte de la investigación posterior, el departamento de recursos humanos necesitaba una lista completa de los sitios web que había estado visitando. A pesar de que ya es un poco complicado extraer estos datos del registro de un único día, los de recursos humanos querían que retrocediera algunas semanas, cosa que no estaba dispuesto a hacer manualmente.

El servidor DHCP (protocolo de configuración dinámica de host) de la compañía indicaba que el equipo del empleado había estado usando la misma dirección IP (en este ejemplo consideraremos que es 192.168.17.54) durante varios meses. Eso, por supuesto, no es excepcional, ya que se trababa de un equipo de escritorio que raramente estaba apagado. Y como el registro del firewall mantuvo un registro de las direcciones IP de origen, sabía que Windows PowerShell podría servirme de ayuda.

El secreto reside en el a menudo olvidado comando Select-String. Y también necesita saber cómo trabajar con las expresiones regulares (cosa que expliqué en el número de noviembre de 2007 de Windows PowerShell).

El comando Select-String aceptará una ruta de acceso de archivos llena de archivos de texto, una expresión regular o una simple cadena que buscar. A continuación, emite cada línea de cada archivo de registro que coincide con la expresión regular o con la cadena sencilla. Para empezar mi tarea, sólo quería conseguir todas las líneas que contuvieran la dirección IP de equipo de escritorio del empleado. Cada línea del archivo de registro contenía una marca de fecha y hora, que era lo que querían los del departamento de recursos humanos.

El comando es el siguiente:

select-string -path c:\logs\*.txt -pattern "192.168.17.54" 
-allmatches –simplematch

El parámetro –simpleMatch especifica que el patrón proporcionado sólo es una cadena sencilla, no una expresión regular. La figura 1 muestra parte de los resultados, que también podrían conducirse a un archivo. Es importante tener en cuenta que los resultados incluyen el nombre de archivo y el número de la línea en los que se encontró la coincidencia, lo cual puede ser muy útil cuando se quiere volver atrás en algún punto para obtener más información.

Cmdlet del mes: Start-Sleep

Este es un cmdlet que puede ofrecer justo lo que se necesita a mitad de un largo día de trabajo, una pequeña siesta. Start-Sleep ofrece una pausa rápida, me refiero a los scripts de Windows PowerShell, por supuesto.

No es raro necesitar una pausa rápida en un script. Por ejemplo, supongamos que necesita iniciar un servicio, esperar unos cuantos segundos para que se inicie y, después, realizar algunas otras tareas que dependen de ese servicio. Start-Sleep es justo lo que necesita para este comportamiento. Al ejecutar Start-Sleep 10, por ejemplo, se hará que el shell se detenga durante 10 segundos. Si usted necesita un control más preciso, puede ejecutar Start-Sleep -mili 100, por ejemplo, para detener durante 100 milisegundos. Start-Sleep suspende completamente el shell, incluyendo los scripts, las canalizaciones y todo lo demás durante el tiempo especificado. Ahora sólo falta que alguien escriba ese cmdlet llamado Start-Nap que tanto llevo esperando.

fig01.gif

Figura 1 Resultados del comando Select-String (haga clic en la imagen para ampliarla)

Coincidencias complejas

Después de proporcionar a los de recursos humanos exactamente lo que pedían, se dieron cuenta de que no era exactamente lo que querían después de todo. Mi informe incluía visitas a diversas direcciones IP, como 207.68.172.246 (el sitio web de MSN®). La siguiente solicitud del investigador consistía en reducir mi informe para que sólo incluyera las visitas a direcciones IP específicas, que ellos habían identificado como pertenecientes a uno de los sitios web en cuestión. En este artículo no revelaré la dirección IP verdadera de la que se hablaba en la investigación. En vez de eso, usaré 207.68.172.246 para este ejemplo (aunque el sitio web de MSN normalmente no sea considerado como inadecuado).

Esta solicitud podría ser un poco más difícil. En el archivo de registro con el que trabajaba, las direcciones IP del origen y el destino estaban una junto a otra y separadas por una coma. Así que sólo tenía que cambiar mi cadena de búsqueda por "192.168.17.54,207.68.172.246" y repetir la búsqueda.

En un archivo de registro más complejo, sin embargo, es posible que hubiera datos de variables almacenados entre las dos direcciones IP, por lo que una coincidencia simple de cadenas no funcionaría. En esa situación, tendría que recurrir a una expresión regular, que también funciona bien en formatos más sencillos de registro, que es lo que demostraré aquí.

Dentro de una expresión regular, el carácter del punto es un comodín para cualquier carácter simple. Y puedo usar la sub-expresión (.)* para buscar cualquier número de caracteres en medio de mis dos direcciones IP. Sin embargo, se debe usar una barra diagonal inversa para obviar los punto literales que aparecen en las propias direcciones IP.

El comando resultante es:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

He eliminado el parámetro –simpleMatch, ya que esta vez estoy usando una expresión regular. Los resultados mostraron sólo las visitas desde el equipo específico del empleado al sitio web identificado como inadecuado. Los resultados también incluían la marca de fecha y hora que quería el investigador. La figura 2 muestra una parte de los resultados que se obtienen al ejecutar un comando como este.

fig02.gif

Figura 2 Resultados de búsqueda acotados que sólo muestran visitas a un sitio específico (haga clic en la imagen para ampliarla)

Puedo optimizar el proceso aún más y dirigir los resultados a Format-Table para usar su habilidad para mostrar columnas calculadas. Puedo hacer que la tabla incluya el nombre del archivo de registro y el número de la línea en la que se encontró la coincidencia, e incluso mostrar la propia línea que coincide. Sin embargo, puedo hacer que el shell reemplace la coincidencia de la expresión regular con una cadena vacía, de manera que sólo se muestre el resto de la línea (en mi ejemplo, la marca de fecha y hora). Esto es un truco avanzado, pero demuestra la forma en que Windows PowerShell puede manipular los datos de cadenas y producir resultados altamente personalizados, todo en una sola línea de comandos:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | 
ft  filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto

La figura 3 muestra un ejemplo de cómo serían mis resultados finales.

fig03.gif

Figura 3 Resultados con formato del comando Select-String (haga clic en la imagen para ampliarla)

El mundo está lleno de cadenas

Proclamo sin ninguna duda que la orientación hacia los objetos de Windows PowerShell es una de sus mayores bazas. Pero a veces, los objetos no son una opción.

Es posible que Windows PowerShell viva en un mundo orientado hacia los objetos. Afortunadamente, el equipo de Windows PowerShell se dio cuenta de que, con frecuencia, el mundo contiene datos externos en forma de cadenas con formato, por lo que crearon el comando Select-String. Armado con Select-String y si conoce las expresiones regulares, puede usar Windows PowerShell para escribir líneas de código que analicen hasta las cadenas más complicadas.

Don Jones es coautor de Windows PowerShell: TFM y autor de decenas de otros libros de TI. Puede ponerse en contacto con él a través de su blog en www.concentratedtech.com.