Adam el Automatizador

Uno de los primeros comandos de Linux que muchos administradores de sistemas aprenden es grep. Esta venerable herramienta ha existido durante décadas y es crucial para el cinturón de herramientas de cualquier administrador. El núcleo de Grep es simplemente la capacidad de buscar en texto plano un patrón RegEx. Grep puede buscar en los archivos de un directorio determinado o en la entrada de flujo para obtener coincidencias. ¿Sabías que PowerShell tiene grep? Bueno..casi.

PowerShell, al ser un lenguaje, es más que un binario de propósito único. Por lo tanto, ¿qué habilidades incorporadas existen para buscar texto plano utilizando patrones RegEx como lo hace grep? En este artículo exploramos las innumerables formas de buscar texto en archivos usando PowerShell.

Explorando el Cmdlet Select-String

Select-String (nuestro grep de PowerShell) trabaja en líneas de texto y por defecto buscará la primera coincidencia en cada línea y luego mostrará el nombre del archivo, el número de línea y el texto dentro de la línea coincidente. Además, Select-String puede trabajar con diferentes codificaciones de archivos, como el texto Unicode, mediante el uso de la marca de orden de bytes (BOM) para determinar el formato de codificación. Si falta la BOM, Select-String asumirá que es un archivo UTF8.

Parámetros de Select-String

  • AllMatches – Normalmente, Select-String sólo buscará la primera coincidencia en cada línea, utilizando este parámetro el cmdlet buscará más de una coincidencia. Se seguirá emitiendo un único objeto MatchInfo para cada línea, pero contendrá todas las coincidencias encontradas.
  • CaseSensitive – Las coincidencias no distinguen entre mayúsculas y minúsculas por defecto, esto obliga al cmdlet a buscar coincidencias que coincidan exactamente con el patrón de entrada.
  • Context – Un parámetro muy útil ya que, se puede definir el número de líneas antes y después de la coincidencia que se mostrará. Al añadir este parámetro se modifica el objeto MatchInfo emitido para incluir una nueva propiedad Context que contiene las líneas especificadas.

Tenga en cuenta que si canaliza la salida de Select-String a otra llamada Select-String, el contexto no estará disponible ya que sólo se busca en la única propiedad resultante MatchInfoline.

  • Culture – Utilizado con el parámetro SimpleMatch, especifica una cultura que debe coincidir con el patrón especificado. Esto incluye opciones como en-USes, o fr-FR como ejemplos. Otras opciones útiles son las opciones Ordinal y InvariantOrdinal es para comparaciones binarias no lingüísticas y Invariant es para comparaciones independientes de la cultura.

Este parámetro se introdujo en PowerShell 7 y no está disponible para versiones anteriores. También hay que tener en cuenta que esto utilizará la cultura actual del sistema, por defecto, que se puede encontrar utilizando Get-Culture.

  • Encoding – Especifica la codificación del archivo de destino a buscar, que por defecto es utf8NoBOM.
    • ascii: Utiliza la codificación para el conjunto de caracteres ASCII (7 bits).
    • bigendianunicode: Codifica en formato UTF-16 utilizando el orden de bytes big-endian.
    • oem: Utiliza la codificación por defecto para MS-DOS y programas de consola.
    • unicode: Codifica en formato UTF-16 utilizando el orden de bytes little-endian.
    • utf7: codifica en formato UTF-7.
    • utf8: codifica en formato UTF-8.
    • utf8BOM: Codifica en formato UTF-8 con marca de orden de bytes (BOM)
    • utf8NoBOM: Codifica en formato UTF-8 sin marca de orden de bytes (BOM)
    • utf32: Codifica en formato UTF-32.

    A partir de PowerShell Core 6.2, el parámetro Encoding también acepta IDs numéricos de páginas de código registradas como 1251 o nombres de cadena como windows-1251.

A partir de PowerShell Core 6.2, el parámetro Encoding también acepta IDs numéricos de páginas de código registradas como 1251 o nombres de cadena como windows-1251.

  • Exclude – Trabajando con el parámetro Path, excluye elementos específicos utilizando un patrón, como *.txt.
  • Include – Al igual que el parámetro ExcludeInclude incluirá sólo los elementos especificados utilizando un patrón, como *.log.
  • List – Sólo devuelve la primera instancia de texto coincidente de cada archivo de entrada. Esto pretende ser una forma rápida y eficiente de recuperar un listado de archivos que tienen contenidos coincidentes.
  • LiteralPath – Esto le dice a Select-String que utilice los valores de entrada, en lugar de interpretar valores como * como un comodín. Si la ruta incluye caracteres de escape, enciérrelos entre comillas simples para no hacer ninguna interpretación.
  • NoEmphasis – En lugar de resaltar la cadena con la que coincide el patrón, desactive el resaltado de las coincidencias. Por defecto, el énfasis utiliza colores negativos basados en los colores del texto de fondo.
  • NotMatch – Buscar texto que no coincida con el patrón especificado.
  • Path – Especificar la ruta de los archivos a buscar. Se permiten comodines, pero no se puede especificar sólo un directorio. El valor predeterminado es el directorio local.
  • Pattern – El patrón para buscar el contenido o los archivos de entrada basado en RegEx.
  • SimpleMatch – Utilice una coincidencia simple en lugar de expresiones regulares. Dado que no se utiliza RegEx, el objeto MatchInfo devuelto no tiene ningún valor en la propiedad Matches.
  • Raw – Imprimir las cadenas coincidentes, sin un objeto MatchInfo. Este es el comportamiento más similar a grep y no a la naturaleza más orientada a objetos de PowerShell.
  • Quiet – Sólo devuelve un $true o $false si se encuentra el patrón.

Usando PowerShell Grep err… Select-String

Por supuesto, saber cómo funcionan los parámetros y opciones de un cmdlet no es exactamente lo mismo que usarlo en un entorno de producción. Vamos a sumergirnos en los ejemplos y ver cómo podemos aprovechar Select-String para facilitar la búsqueda de coincidencias de texto.

Hay tres formas en las que podemos utilizar Select-String para encontrar coincidencias.

  • Entre el texto entrecomillado al cmdlet Select-String, es decir, introducir el texto.
  • Utilizando el texto almacenado en una variable, pasar la variable al parámetro InputObject.
  • Utilizar el parámetro Path para especificar los archivos donde buscar el texto.

Los archivos que estamos utilizando para probar esto son contenidos generados aleatoriamente, pero del mismo tipo que suelen encontrarse en los sistemas de producción.

Comparación simple en archivos

Comenzando con un ejemplo muy simple, busquemos Joe en un puñado de archivos CSV.

Select-String -Path "Users\*.csv" -Pattern "Joe"
Demostrando una simple coincidencia de patrón Select-String.
Demostrando una simple coincidencia de patrón Select-String.

Como puedes ver, esto es bastante simple, vemos como Joe está resaltado en la línea con el resto de los datos. Pero, ¿qué datos se devuelven realmente aquí? Veamos todas las propiedades de una coincidencia devuelta.

Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object * -First 1
Mostrando las propiedades devueltas de una coincidencia Select-String.
Mostrando las propiedades devueltas de una coincidencia Select-String.

Tenemos un par de propiedades aquí que son útiles. En particular el linepathpattern, y matches. La mayor parte de lo que queremos saber está en la propiedad matches.

Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object -ExpandProperty Matches -First 1
Enumerando la propiedad Matches y los datos disponibles.
Enumerando la propiedad Matches y los datos disponibles.

Aquí puedes ver como aunque hemos utilizado una expresión simple, esta sigue siendo una expresión RegEx y los detalles posteriores disponibles.

¿Y si buscamos varios valores diferentes utilizando patrones separados por comas? Esto es útil ya que esto realmente define tres patrones diferentes y no un valor RegEx complejo.

Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry"
Devolviendo múltiples coincidencias de una búsqueda Select-String.
Devolviendo múltiples coincidencias desde una búsqueda de cadena selectiva.

Puedes ver cómo es el caso, si seleccionamos sólo el filenamepattern, y line de nuestra búsqueda.

Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry" | Select-Object FileName, Pattern, Line
Filtrar los resultados de una coincidencia múltiple de Select-String.
Filtrar los resultados de una coincidencia múltiple de Select-String.

Comparaciones RegEx más complejas

Ahora que hemos demostrado algunos de los métodos de coincidencia más simples, ¿qué tal si utilizamos RegEx más para buscar patrones más útiles? Los tres ejemplos aquí buscan direcciones de correo electrónico, direcciones IP y números de la seguridad social (SSN). Los patrones utilizados aquí no son la única manera de construir una búsqueda RegEx, y puede haber maneras más fáciles. PowerShell Grep (Select-String) es un cmdlet bastante avanzado.

Veamos si los correos electrónicos están contenidos en nuestros archivos. El uso de una coincidencia RegEx algo compleja, como se muestra a continuación, demostrará la búsqueda de esas coincidencias.

Select-String -Path "Users\*.csv" -Pattern '\\b+\.{2,4}\b' | Select-Object -First 10
Demostración del uso de RegEx para hacer coincidir datos.
Demostración del uso de RegEx para cotejar datos.

Por supuesto, lo más preocupante podría ser si hubiera SSNs incluidos en un archivo. Una coincidencia muy simple para esto sería la siguiente.

Select-String -Path "Users\*.csv" -Pattern '\d\d\d-\d\d-\d\d\d\d' | Select-Object -First 10
Demostrando una simple búsqueda RegEx de SSN.
Demostrando una simple búsqueda RegEx de SSN.

Finalmente, ¿qué pasa si queremos buscar algunas direcciones IP en nuestro archivo? Usando otra expresión RegEx para buscar ese patrón, hace un trabajo rápido.

Select-String -Path "Users\*.csv" -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' | Select-Object -First 10
Demostrando una simple búsqueda RegEx de direcciones IP.
Demostrando una simple búsqueda RegEx de direcciones IP.

Una advertencia sobre este RegEx. Técnicamente, esto coincidirá con valores hasta 999.999.999.999 que es una IP no válida. Puedes construir expresiones RegEx más precisas que serán más largas, pero es una compensación dependiendo de lo que estés buscando hacer.

Búsqueda con Contexto

El contexto es muy útil en la resolución de problemas, ayuda a explicar lo que está sucediendo antes de que ocurra un evento y después. Por ejemplo, busquemos en un log de Apache y encontremos este suspendedpage.cgi texto.

Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -First 1
Buscando una línea en un log de Apache.
Buscando una línea en un registro de Apache.

El > simple indica la línea coincidente, y hay una línea antes de la coincidencia y después de la coincidencia. En este ejemplo, esto podría indicarnos que el bot de Google estaba buscando robots.txt y, lamentablemente, recibió un resultado suspendedpage.cgi en su lugar. A continuación, fue a probar la página de inicio y quizás obtuvo el mismo error.

¿Qué contiene exactamente la propiedad context tal y como la emite el objeto MatchInfo? Si ampliamos esa propiedad, puedes ver que hay PreContent y PostContent. Esto significa que puedes manipular esto más adelante si es necesario.

Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -ExpandProperty Context -First 1 | Format-List
Demostrando la propiedad Context.
Demostrando la propiedad Context.

Otros ejemplos de búsqueda a través de archivos de registro se encuentran en artículos como Making Sense of the Microsoft DNS Debug Log que demuestra el uso de Select-String para mirar a través de un registro de depuración de DNS. El grep de PowerShell es fuerte en ese post.

Conclusión

Grep es una herramienta increíblemente útil en el mundo Linux, y Select-String ofrece gran parte de la misma funcionalidad en el mundo PowerShell. La adición de la naturaleza orientada a objetos de PowerShell sólo sirve para mejorar la utilidad y la utilidad que el cmdlet ofrece.

Para muchos administradores de sistemas, ser capaz de buscar rápida y eficientemente los archivos de registro sobre diversos tipos, junto con la comprensión del contexto, es una habilidad increíblemente importante y necesaria. PowerShell Select-String hace que esto sea fácil de hacer y ahorra innumerables horas de solución de problemas!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *