Powershell basics: Las tuberias

¡Hola a todos!

En ocasiones previas habéis visto en este blog el uso de PowerShell (que también se suele abreviar como PS) para realizar tareas administrativas. Y la verdad es que como herramienta de administración de sistemas Windows es insuperable. Así que… ¿Por qué no hablar sobre algunos de los conceptos más importantes de PowerShell?

La base son los objetos

Ante todo, lo más importante a la hora de trabajar con PowerShell es entender los datos con los que trabaja. A diferencia de otros sistemas de scripting, que nos devuelven datos en forma de texto, en PowerShell lo que se nos devuelve son objetos. Objetos que en la consola tienen una representación textual, pero que pueden manipularse de formas mucho más complejas.

Sin ir más lejos, cuando escribimos el comando “ls” o “dir”, en realidad estamos ejecutando el cmdlet “get-childitem”, el cual nos devuelve una lista de archivos. Ahora bien, como ya hemos dicho, lo que PS nos devuelve son objetos.

ls ls_0

Esto lo podemos comprobar, sin ir más lejos, si deseamos solicitar un elemento concreto de la lista de objetos que ls nos devuelve. Pero aún se puede ir más lejos. PowerShell nos proporciona un cmdlet que nos permite analizar la estructura de un objeto. Este cmdlet se llama “Get-Member”, y nos devuelve información completa sobre métodos y propiedades del objeto que le hemos pasado como parámetro. En este caso, los métodos son funciones que el objeto puede ejecutar, mientras que las propiedades son datos (objetos) que se pueden consultar.

ls_getmember

En este caso, se puede ver cómo PS extrae la información del objeto de tipo “DirectoryInfo”, y muestra diversos métodos que se pueden usar para manipular o extraer más información de dicho objeto. Dependiendo del tipo de objetos con los que estemos trabajando, utilizar el cmdlet get-member va a ser muy útil para inspeccionar los resultados, y obtener no sólo información sobre la estructura del objeto, sino acceder a funciones que permiten al objeto realizar acciones más avanzadas. ¿Cómo se ha conseguido comunicar el cmdlet “ls” con el “get-member”? Pasándole información por una tubería.

Tuberías (Pipeline)

En la mayoría de sistemas de scripting se incluye una funcionalidad conocida como “tubería” y como se puede imaginar, el nombre de esta característica es una metáfora del funcionamiento de la misma. ¿Para qué se usa una tubería? Para conectar un origen de datos a un destino que los consuma. En el caso de PowerShell, una tubería permite hacer un streaming de objetos desde el cmdlet que los está produciendo (como resultado) a otro cmdlet que los va a consumir (para procesar los objetos, transformarlos, ordenarlos, etc).

Entre las características más vitales de las tuberías, destacaría las siguientes:

  • Las tuberías conectan dos cmdlets. Esto no impide que un cmdlet que está recibiendo datos desde una tubería pueda enviar los resultados a través de otra. Es decir, se pueden encadenar tuberías para conectar múltiples cmdlets sin ningún tipo de limitaciones.
  • El streaming de objetos a través de las tuberías se realiza uno a uno. Esto es importantísimo en términos de rendimiento, y en demasiadas ocasiones se suele pasar por alto. Se comenta con mayor detalle en la siguiente sección.

¿Cómo se usan las tuberías?

Para interconectar la salida de un cmdlet con la entrada de otro se usa el carácter especial “|”. Éste carácter indica a PowerShell que debe enviar los objetos de respuesta del cmdlet a la izquierda del mismo hacia el cmdlet a la derecha. Ya se ha visto un ejemplo práctico de funcionamiento de la tubería cuando se presentó el cmdlet “Get-Member”, el cual, como ya se indicó, toma como entrada objetos.

Así pues, un ejemplo de tubería muy sencilla sería “Get-ChildItem | select-Object * | Out-Gridview”. Esta tubería devuelve una ventana (Out-Gridview),8con todos los atributos de los objetos (Select-Object *) devueltos por el cmldet Get-ChildItem.

outGridview

Consideraciones de rendimiento

A la hora de manipular datos a  escala masiva, siempre va a aparecer la siguiente disyuntiva: Consumo de RAM vs Consumo de Tiempo.

Usualmente, la forma más rápida de procesar datos consiste en almacenar el resultado de la ejecución del cmdlet en un array, y procesarlo. Pero esto significa almacenar toda la información devuelta en memoria. En el caso de, por ejemplo, consultar información de un Directorio Activo con decenas o cientos de miles de objetos, la consulta cargará todos los objetos en memoria. Y esto, en máquinas con recursos limitados, como mínimo va a provocar la ralentización de todos los servicios de la misma. Incluyendo la propia ejecución del script.

Por otro lado, en vez de cachear toda la información en RAM, se puede usar una técnica diferente para procesar esa enorme cantidad de información. Y ya se ha hablado de ella en este artículo. Las tuberías pasan los objetos devueltos  de uno en uno. Esto significa que se pueden procesar las decenas o cientos de miles de objetos individualmente, sin colapsar la memoria del sistema. Como contrapartida, el tiempo de ejecución del script suele aumentar drásticamente, debido al overhead provocado por el movimiento de los objetos entre cmdlets.

En ocasiones, no va a ser posible elegir entre un tipo de optimización u otro. Por ejemplo, si el cmdlet/función que suministra los resultados incluye algún mecanismo de caducidad por el que transcurrido cierto tiempo desde la ejecución del mismo, se considera que los resultados son viejos y por tanto no válidos. Esto puede suceder en funciones de búsqueda o consulta. En este caso, habría que acudir obligatoriamente al mecanismo de cacheado en RAM, ya que los resultados cacheados no van a “caducar” durante la ejecución del script.

 

¡Y esto es todo de momento! Esperamos que con estos consejos sobre el uso de tuberías y cómo afectan al consumo de recursos del sistema podáis escribir scripts más eficaces, siempre adaptándolos a las necesidades de cada momento.

 

Enlaces de Interés:

http://blogs.technet.com/b/heyscriptingguy/archive/2014/06/30/back-to-the-basics-part-1-learning-about-the-powershell-pipeline.aspx

Deja un comentario

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