powershell-logoPara los administradores de sistemas más avanzados, uno de los puntos débiles de Windows frente a otros sistemas operativos ha sido tradicionalmente  la capacidad de administración de éste desde línea de comandos.

Windows siempre ha sido un sistema operativo muy fácil de administrar visualmente. En general todos los productos de Microsoft lo son, y esta ha sido siempre una de las principales causas de su preponderancia como sistema operativo. Sin embargo esta facilidad de uso, basada en consolas gráficas y asistentes, ha sido tradicionalmente un arma de doble filo y fuente de controversias. Por un lado la sencillez con la que se realiza cualquier tarea hace que ciertas personas ganen excesiva confianza. En muchas ocasiones esta sencillez se convierte en un grave problema que lleva a que los sistemas estén mal administrados, debido a que no se ha profundizado bien en los conceptos necesarios para una buena gestión (la sencillez de un asistente no alienta tampoco el meterse en grandes honduras). Por otra parte ha sido también un problema porque esas mismas interfaces gráficas que tanto facilitan el trabajo más común, se convierten en un estorbo a la hora de realizar tareas complejas (formadas por otras tareas individuales más simples) que precisen de cierto grado de automatización.

La consola del sistema tradicional (cmd) nunca ha sido especialmente generosa en características, y desde luego está a años luz de los “shell” de UNIX en los que se inspira. Los clásicos archivos .bat son muy limitados y es un dolor realizar con ellos cualquier interacción avanzada con el usuario.

Hace ya bastantes años Microsoft incorporó a sus sistemas operativos un subsistema de automatización llamado Windows ScriptingHost (WSH) que trataba de acortar distancias con la administración de otros entornos. WSH se basa en la escritura de código en lenguajes de script, y soporta multitud de ellos (JavaScript, VBScript, Perl, Python, TCL, Ruby, PHP... hasta COBOL!). Estos scripts permiten crear tareas mucho más complejas que con un simple .bat, además de brindar acceso a la funcionalidad de cualquier objeto COM automatizable, incluyendo por ejemplo acceso a datos, a la red o a servicios web, y las funcionalidades de diversas aplicaciones con interfaz automatizable (como las de Office entre muchas otras).

Realmente WSH supuso una gran mejora sobre lo existente hasta entonces (la línea de comandos de MS-DOS) pero también presentaba un importante problema y es que, al fin y al cabo, los administradores no tienen porque ser también programadores. Si bien es cierto que VBScript o JScript son lenguajes sencillos cuyos rudimentos se aprenden rápido, para hacer uso de las funcionalidades de administración que necesitamos es necesario asimilar el uso de objetos COM que no son nada sencillos en general. Por ejemplo WMI (Windows Management Instrumentation) o ADSI (para acceso al directorio activo).

Esta es una grave limitación puesto que para sacarle partido a WSH hay que saber programar a un cierto nivel, aparte de ser difícil de depurar y requerir mucha ceremonia (en forma de archivos XML) para combinar entre sí la funcionalidad de diversos archivos WSH.

MSH/Monad

Por fin, allá por el año 2002, Microsoft se decidió a coger al toro por los cuernos y poner remedio a la situación de su administración desde línea de comandos. Para ello empezó a desarrollar una herramienta de administración llamada Monad o MSH (Microsoft Shell) que estaba destinada a cambiar la forma en que se administraba Windows, ofreciendo lo mejor de otros sistemas operativos (como el shell bash de UNIX), pero ofreciendo mucha más potencia y capacidad de ampliación y encadenamiento de órdenes.

La palabra Monad que se usó para el nombre en clave del producto (como es habitual en Microsoft sus nombres en clave molan mucho más que los nombres finales de los productos), tiene un origen bastante rebuscado. El apelativo proviene de la filosofía de Leibniz llamada “Monadología”, que dice fundamentalmente que cualquier cosa es en realidad una composición formada a partir de otras cosas más pequeñas, siendo las más pequeñas de todas las “Mónadas” (o Monad en ingles). Y es que precisamente la gran aportación de Monad a la administración fué que su núcleo se basaba en la transferencia de objetos a través de un gran conducto común.

Si eres usuario de UNIX/Linux estarás pensando ahora mismo: “Pues vaya cosa, eso de los conductos (pipes) hace décadas que lo inventó UNIX”. Y es verdad. Pero la palabra clave en la frase anterior no es “conducto” sino “objeto”. En los sistemas basados en UNIX, como Linux, Solaris o Mac OS X, se pueden combinar diversos comandos entre sí a través de conductos (pipes) que toman como entrada la información generada por los anteriores, realizando así tareas complejas a partir de otras más sencillas. El problema es que la transferencia de información entre ellos se realiza mediante texto (ASCII) puro y duro y muchas veces lejos de estar estructurado. Esta transferencia implica tener que saber interpretar los datos recibidos (que siempre deben estar de la misma forma) y analizar las cadenas para obtener los fragmentos de información que sean necesarios, todo ello antes de llevar a cabo el siguiente proceso en sí. Si toda esta información se transfiriese entre unos comandos y otros de forma estructurada, estándar y fácilmente accesible toda la administración del sistema se volvería mucho más sencilla.

Monad se fundamentaba en esta noción, junto a una estrecha asociación con la plataforma .NET, y facilitando el uso de conceptos diversos sacados de sitios tan dispares como el Shell de Unix, la reflexión de .NET o la sintaxis de SQL.

Pero vamos a ver... ¿no se suponía que lo que buscábamos era algo potente pero que no nos obligase a saber programar?. Efectivamente. Aunque suene complejo, la ventaja de todo esto que a pesar de lo que acabo de decir, Monad era muy fácil de utilizar para los administradores, y al mismo tiempo permitía que los programadores pudieran extender sus funcionalidades de manera muy flexible para acercar cualquier utilidad específica a los primeros. Unos tendrán la oportunidad de aprender algo más sobre los objetos .NET y los otros podrán ampliar su radio de acción hacia el ámbito de los sistemas.

PowerShell

Cuando por fin se lanzó la versión definitiva de Monad a principios del año 2007, unos pocos meses después de Windows Vista y Windows Server 2008, sistemas para los que estaba diseñado. Su nombre oficial entonces fue Windows PowerShell (¿tengo razón o no en lo de los nombres en clave?). Actualmente va por su versión 4, aparecida en octubre de 2013.

PowerShell se basa igualmente en esa "mónadas" de las que hablaba antes, y puede ejecutar básicamente cuatro tipos de mónadas o comandos individuales:

  • cmdlets: que son programas escritos en .NET y pensados específicamente para trabajar con PowerShell.
  • Funciones Powershell
  • Programas ejecutables sueltos: como ya ocurría con los archivos .bat. Los ejecuta en un proceso separado.
  • Scripts de PowerShell (.ps1): son parecidos a los archivos .bat y ejecutan conjuntos más o menos complejos de comandos/mónadas, comunicados o no entre sí, para realizar tareas lo complejas que necesitemos.

 

Existen programas PowerShell para casi todo, y todos los productos importantes que se ofrecen con un sesgo empresarial, ofrecen comandos PowerShell para facilitar sus administración. Por supuesto todos los de Microsoft (desde SQL Server a Exchange, pasando por SharePoint, IIS, etc...) tienen completos juegos de comandos para PowerShell y de hecho incluso existen en algunos de ellos ciertas características concretas que solo se pueden administrar con PowerShell y no gráficamente.

Ejemplos sencillos de uso

Para comprender un poco mejor el funcionamiento de PowerShell vamos a ver un ejemplo de utilización sencillo.

Los comandos de PowerShell constan de parejas de verbos y nombres separados entre sí por un guión (en las primeras betas allápor 2002 era una barra inclinada). Estos comandos/mónadas pueden combinarse con otras parejas de acciones para realizar tareas más complejas fáciles de entender con sólo leerlas.

Por ejemplo, cómo podemos obtener una lista de los procesos que se están ejecutando en el servidor. Basta con escribir:

get-process

para obtener en la línea de comandos información al respecto:

PowerShell-get-process

Lo cual está muy bien, pero de momento no vemos muchas ventajas respecto al comando ‘ps’ de UNIX ¿no?

La verdadera diferencia estriba en que, aunque se imprime en la pantalla un puñado de información que parece texto, en realidad lo que el comando ha generado es una colección de objetos .NET (en este caso de tipo System.Diagnostics.Process). Estos objetos se pueden utilizar directamente desde otros comandos a los que se “encaucen”, accediendo a sus propiedades y métodos de forma sencilla. Es decir, al contrario que en UNIX se recibe información estructurada y verdaderos objetos, no simplemente cadenas de texto que hay que procesar (¿se cambia una coma y qué pasa?). De esta manera es muy fácil escribir cualquier programa para explotar la información que contienen o utilizar sus métodos para hacer cosas concretas con ellos (por ejemplo detenerlos o cambiar su prioridad).

Así por ejemplo, si queremos que el resultado del comando anterior se muestre en una rejilla de datos, dentro de una ventana, con toda la información en lugar de en un simple listado de texto sólo hay que escribir:

get-process | Out-GridView

ya que el comando Out-GridView recoge la colección de objetos y los enlaza a una rejilla en una ventana creada para la ocasión:

PowerShell-get-process-out-gridview

pulsa para aumentar

Como podemos observar, la ventana ofrece la capacidad de ordenar y filtrar la información de manera simple, y nos sirve no solo para los procesos sino para cualquier otra información que le queramos pasar. Súper-cómodo (Nota: la rejilla tiene una limitación y es que no permite exportar la información y además el máximo de columnas que puede mostrar es de 30, por lo que si cada objeto tiene más de 30 propiedades, el resto no aparecerán, ojo).

Además podemos crear nuestras propias funciones especializadas de manera sencilla. Por ejemplo, imagínate que queremos crear un comando de tipo función PowerShell que sirva para exportar cualquier colección de objetos a Excel. Es muy sencillo, la llamaremos Out-Excel y se haría con 3 simples líneas de código:

function Out-Excel
{
  param($Path = "$env:temp\$(Get-Date -Format yyyyMMddHHmmss).csv")
  $input | Export-CSV -Path $Path -UseCulture -Encoding UTF8 -NoTypeInformation
  Invoke-Item -Path $Path
}

El parámetro $input recibe el resultado del comando anterior, y en este caso lo que hacemos es crear en la carpeta temporal un archivo .csv con la fecha actual como nombre (Get-date -Format) y exportarlo a CSV con el comando Export-CSV, lanzando el programa correspondiente a los archivos .csv (normalmente Excel si lo tenemos instalado) con el comando Invoke-Item.

Ahora basta con usar | Out-Excel para obtener los resultados en una Excel:

PowerShell-Out-Excel

Pulsa para aumentar

Está bien, ¿verdad? :-)

Lo importante aquí es que, independientemente de lo que se concatene en el conducto, cada fragmento de la tarea es un objeto .NET que recibe para su consumo otros objetos .NET de una manera genérica, y que éstos a su vez generan otros objetos .NET cualquiera que pueden pasarse a un hipotético siguiente comando que los procesará usando los mismos mecanismos internos.

Antes hablábamos de que PowerShell también tomaba algunos conceptos de las consultas SQL a bases de datos. Veamos un ejemplo de esto. Supongamos que queremos localizar aquellos procesos del sistema que están consumiendo más de 50 MB de memoria virtual:

Powershell-consulta-memoria-virtual

esta expresión hará el trabajo. Fíjate en que lo único que hemos añadido es un elemento más al conducto que toma como entrada el resultado del elemento anterior y que en este caso se encarga de filtrar dicha entrada (la lista de procesos) usando un comando where, ofreciendo como resultado propio un subconjunto filtrado según el criterio que se expresa. El operador –gt implica la comparación “mayor-que”, habiendo otros operadores análogos para el resto de comparaciones posibles. Esta sintaxis (que como veremos enseguida se parece muchísimo a la del lenguaje Perl) es tal vez poco intuitiva para un programador de scripts, pero más familiar seguramente para un administrador de sistemas.

Sigamos con las analogías con SQL. Por ejemplo, vamos a obtener la información de los procesos ordenada de mayor a menor por la memoria virtual ocupada:

get-process | where {$_.virtualmemorysize –gt 500000000} | sort-object virtualmemorysize -descending

De este modo lo ordenamos por la memoria virtual de manera descendente.

Mejor aún, que nos lo agrupe según el fabricante del software:

Powershell-Group-Object

Muy fácil ¿verdad?.

Aparte de obtener información, por supuesto, se pueden llevar a cabo todo tipo de acciones sobre los objetos que se devuelven.

Por ejemplo, el siguiente comando cerraría los procesos que estén consumiendo más de 50 MB:

get-process | where {$_.virtualmemorysize –gt 500000000} | stop-process

para lo cual usa el cmdlet Stop-Process.

incluso a este ultimo comando (y a muchos otros) se le puede pasar la opción –whatif para que en lugar de realizar su función informen sobre lo que harían en caso de ejecutarlos. En nuestro último ejemplo añadiendo –whatif  al final se mostraría una lista de acciones que se realizarían sobre los procesos, o sea, sabríamos que procesos se eliminarían sin ejecutarlo realmente:

PowerShell-WhatIf

En resumen

Con este texto he pretendido dar una visión general introductoria a qué es Windows PowerShell, de dónde viene, cuáles son sus motivaciones, en qué es diferente (y mejora) otros shell tradicionales, y cómo usarlo.

El mayor problema que tiene es que los administradores de sistemas tradicionalmente le tienen alergia a programar, y los programadores le tienen alergia a administrar sistemas ;-) Sin embargo es una forma estupenda de aunar ambos mundos y de conseguir una potencia antes inimaginable en el mundo Windows.

Como programador de la plataforma .NET aprender PowerShell y, sobre todo, aprender a programar módulos de PowerShell puede abrirte un gran campo de trabajo, puesto que no hay mucha gente que se dedique a ello.

Aquí os dejo algunos recursos adicionales:

¡Espero que te haya resultado interesante!

💪🏻 ¿Este post te ha ayudado?, ¿has aprendido algo nuevo?
Pues NO te pido que me invites a un café... Te pido algo más fácil y mucho mejor

Escrito por un humano, no por una IA