Windows PowerShellTrabajar sin un script

Don Jones

Siempre que hablo con la gente acerca de Windows PowerShell (ya sea en una conferencia, en el grupo de noticias público de Windows PowerShell o en mi sitio web), conozco a administradores que me dicen que "esperarán" para aprender Windows PowerShell. ¿Por qué? La razón que dan con mayor frecuencia es que

"no tienen tiempo de aprender a redactar en este momento".

Es un caso habitual. En general, los administradores estamos bastante atareados, y no solemos tener mucho tiempo libre para aprender una tecnología nueva. Pero tenemos que ir siempre hacia adelante, aprendiendo software nuevo como Windows Vista®, Windows Server® 2008 y Exchange Server 2007, para estar a la vanguardia de las tecnologías vitales para nuestros trabajos. Y Windows PowerShell™ es una parte importante de estas tecnologías.

Otro motivo que citan a menudo los administradores para postergar el aprendizaje de Windows PowerShell es que tienen "miedo de convertirse en programadores", tal y como me dijo un compañero administrador. Bueno, pues en eso yo le puedo ayudar. Se sorprenderá si le digo que puede hacer cosas realmente asombrosas con Windows PowerShell sin escribir ni una sola línea de código.

Prepararse para la canalización

He escrito antes acerca de la flexible y eficaz canalización orientada a objetos que usa Windows PowerShell. Aunque las palabras "orientado a objetos" le hagan sospechar que me estoy adentrando en el terreno de los programadores, no tema. Uno de los aspectos de la canalización que más me gustan es la forma de usarlo interactivamente. Le puede dar resultados inmediatos y permite refinar fácilmente los resultados para llegar a obtener exactamente lo que desea. Por ejemplo, supongamos que quiero obtener un inventario de espacio libre en disco para varios equipos remotos. Ahora supongamos que tengo los nombres de dichos equipos listados en un archivo de texto llamado C:\equipos.txt. Es un archivo de texto simple con un nombre de equipo por línea, mucho menos complicado que una base de datos.

Para empezar, intentaré ver si puedo recuperar esta información desde mi equipo local. A fin de cuentas, si yo consigo en un equipo, no resultará difícil hacerlo en varios. Y recuerde que no habrá que escribir código. Lo haré todo interactivamente en el shell y obtendré resultados justo después de presionar Intro.

Una sugerencia sobre este tipo de tareas. Si desea inventariar información de administración de equipos remotos, probablemente usará Windows® Management Instrumentation (WMI). Ahora suponga que, en este ejemplo, lo único que sé es que necesito usar WMI. Así que entro en Live Search y escribo "windows wmi liberar espacio en disco" como término de búsqueda. Aparecen varios resultados que contienen las palabras "Win32_LogicalDisk". Parece una clase de WMI, y podría ser la que necesito. Ni me molesto en hacer clic en ninguno de estos resultados de búsqueda. En vez de eso, escribo "Win32_LogicalDisk" como nuevo término de búsqueda y el primer resultado es de una página de documentación sobre Win32_LogicalDisk en el sitio de MSDN ® (msdn2.microsoft.com/aa394173.aspx). Así que entro en esa página y veo que una de las propiedades de esta clase es FreeSpace, lo cual suena muy prometedor.

Encontrar un Cmdlet

Para el paso siguiente, necesito encontrar un cmdlet que pueda recuperar las propiedades de una clase WMI. Uno de los aspectos más notables de Windows PowerShell es que tiene unas fantásticas características integradas de autodetección, es decir, el shell le ayuda a descubrir sus capacidades. Así que escribo Help *wmi* para averiguar qué sabe el shell acerca de cómo trabajar con WMI. Los resultados, que se muestran en la figura 1, son el alias Gwmi y el cmdlet al que señala, Get-WMIObject. Básicamente, hay dos formas de tener acceso a la misma funcionalidad, de modo que no hay muchas opciones a elegir. Dado que hacen lo mismo y que Gwmi es un nombre más corto, usaré éste:

Figura 1 Información que tiene el shell acerca de cómo trabajar con WMI

Figura 1** Información que tiene el shell acerca de cómo trabajar con WMI **(Hacer clic en la imagen para ampliarla)

PS C:\> gwmi win32_logicaldisk

Tenga en cuenta que Windows PowerShell no distingue entre mayúsculas y minúsculas: sabe que los administradores no tenemos tiempo para detalles irrelevantes como presionar la tecla Mayús.

Los resultados de este comando, que aparecen en la figura 2, incluyen mis cinco unidades de disco locales y propiedades FreeSpace correspondientes, que aparecen en la lista como bytes. En la lista también se incluye una propiedad DriveType para cada una de estas unidades, y aparecen valores de 2, 3, y 5 en mi equipo.

Figura 2 Todas mis unidades locales y las propiedades FreeSpace correspondientes

Figura 2** Todas mis unidades locales y las propiedades FreeSpace correspondientes **(Hacer clic en la imagen para ampliarla)

Cmdlet del mes

Es posible que haya usado Get-Content para leer el contenido de un archivo de texto. Este comando trata cada línea del archivo como un objeto [string], y pasa los objetos a la canalización para que trabajen con ellos otros cmdlets. Pero Get-Content tiene algunas opciones que lo hacen más flexible: el parámetro -readCount, por ejemplo, permite especificar cuántos objetos [string] se pasan a la canalización a la vez (el valor predeterminado es enviarlos todos), mientras que el parámetro -totalCount controla el número total de líneas que se leen desde el archivo. Ambos parámetros son útiles para trabajar con archivos muy grandes donde es posible que no desee procesar el archivo entero de una sola vez por motivos de rendimiento.

Este es otro parámetro útil. El parámetro –encoding permite leer correctamente una amplia variedad de tipos de codificación de archivos, como Unicode, ASCII, UTF7, UTF8, entre otros. Para ver una lista completa de tipos de codificación compatibles, ejecute help gc (gc es un alias de Get-Content).

Refinar los datos

En este punto tengo dos problemas. Primero, no me interesa ninguna de las demás propiedades, sólo me interesa el espacio libre (FreeSpace). Segundo, no quiero saber nada acerca del espacio disponible para unidades ópticas, unidades extraíbles o unidades de red; sólo me interesan los discos duros locales. Quizá la propiedad DriveType me puede ayudar a distinguir entre los distintos tipos de unidad. Vuelvo al explorador web y veo que la documentación contiene una tabla que explica lo que representan los distintos valores DriveType. Sólo quiero los que tienen un DriveType de 3, que indica que la unidad es un disco duro local. Al no haber hecho esto nunca, decido mirar si el comando Gwmi admite algún tipo de filtrado. Al ejecutando Help Gwmi –full se muestran detalles acerca del funcionamiento del comando, incluidos varios ejemplos. Encuentro un parámetro que parece útil, –filter, y decido intentar ejecutar lo siguiente:

gwmi win32_logicaldisk -filter "drivetype = 3"

¡Funcionó! Mi lista de unidades ahora sólo contiene los discos fijos locales. Así queda resuelto el segundo problema; ahora necesito solucionar el primero: deshacerme de todas las propiedades que no me interesan.

Ejecuto Get-Command para mostrar todos los cmdlets de Windows PowerShell y me encuentro con Select-Object. La descripción dice que "selecciona las propiedades especificadas de un objeto o de un conjunto de objetos". Así que intento esto:

gwmi win32_logicaldisk -filter "drivetype = 3" | select freespace

Si canalizo los resultados de Gwmi a Select (el alias de Select-Object) puedo obtener la propiedad que necesito. Pero vaya. Estos resultados no son lo que esperaba, ya que lo único que tengo es una lista de números y ya no sé qué unidad corresponde a cada listado de espacio disponible. Así que vuelvo a la documentación y veo que la propiedad DeviceID contiene la letra de unidad. Reviso rápidamente mi comando y lo vuelvo a probar:

gwmi win32_logicaldisk -filter "drivetype = 3" | select deviceid,freespace

¡Perfecto! Y ya que sólo se muestran dos propiedades, el shell puede mostrar la información en una tabla ordenada. El mes próximo explicaré cuándo decide Windows PowerShell usar listas y tablas.

Cálculos

He recuperado información sobre el espacio disponible, pero está en bytes y esta medida no es tan útil como lo sería en megabytes o en gigabytes. Quizás no me interesa tanto la propiedad FreeSpace, como un valor calculado a partir de la propiedad FreeSpace. El cmdlet ForEach-Object (o uno de sus muchos alias, como %) puede resultar útil en este sentido. Este cmdlet permite usar una variable especial, $_, para referirse al disco lógico actual, y permite tener acceso a todas las propiedades de cada disco por separado y realizar algunos cálculos. Aquí puede ver el comando modificado por mí:

gwmi win32_logicaldisk -filter "drivetype = 3" | % { $_.deviceid; $_.freespace/1GB }

Lo único que he hecho es eliminar Select y sustituirlo por el alias de ForEach-Object (%). El cmdlet sólo necesita que especifique qué hacer con cada Win32_LogicalDisk obtenido, y le he indicado que obtenga la propiedad DeviceID y divida la propiedad FreeSpace por un gigabyte (Windows PowerShell "distingue" entre KB, MB y GB) para que el resultado se exprese en gigabytes.

Varios equipos

Ahora que funciona para un equipo, es hora de hacer que funcione con varios equipos. Sé cómo obtener el contenido de un archivo de texto. Esto se hace de la misma forma que en los viejos tiempos de MS-DOS®: usando el comando Type, que en Windows PowerShell resulta que es un alias de Get-Content:

Type c:\computers.txt

Lo que quiero hacer es tomar cada uno de estos equipos, y para cada uno, realizar el comando WMI que ya he preparado. La expresión "para cada uno" indica un cmdlet concreto: ForEach-Object. Vamos directos al grano, y echemos un vistazo al comando final:

type c:\computers.txt | % { $_; 
gwmi –computername $_ win32_logicaldisk -filter "drivetype=3" | % { $_.deviceid; $_.freespace/1GB} }

De un poco de miedo, ¿no? Debido a que uso exclusivamente de alias en lugar de nombres de cmdlet, cuesta leer el resultado. No obstante, es bastante fácil de descifrar si se hace de bit en bit:

  • Empecemos "escribiendo" el contenido de mi archivo de texto.
  • Canalizo el contenido a ForEach-Object.
  • ForEach-Object genera el artículo actual, mediante la variable $_ (se trata del nombre del equipo actual).
  • A continuación, ForEach-Object ejecuta mi comando WMI, que tiene otra llamada ForEach-Object.

Puede ser de ayuda expandir los nombres de alias en nombres de cmdlet. Aquí está el mismo comando, pero esta vez he deletreado los cmdlets y he fragmentado el comando en líneas individuales para que se vea más fácilmente cada sección:

Get-Content C:\Computers.txt | 
ForEach-Object { 
 $_; Get-WMIObject –computername $_ 
Win32_LogicalDisk -filter "DriveType=3" | 
 ForEach-Object { 
 $_.DeviceID; $_.FreeSpace/1GB
 }
}

Los resultados (que no resultan atractivos, pero sí funcionales) se muestran en la figura 3.

Figura 3 Los resultados finales

Figura 3** Los resultados finales **(Hacer clic en la imagen para ampliarla)

No se necesita scripting

El objetivo de esta explicación es demostrar que puede usar Windows PowerShell sin necesidad de scripting. Con tan sólo algunos ejemplos como este, además de una pequeña estudiar un poco el propio Windows PowerShell, puede encontrar algunos de los bits que necesita para realizar cualquier tarea que se proponga.

La idea es que Windows PowerShell ha venido para quedarse. ¿Por qué no empieza ahora a aprender a usarlo? Es posible que se esté preguntando cómo había podido vivir sin él. ¡No permita que la palabra scripting le impida sumergirse en este apasionante mundo!

Don Jones es el principal gurú de scripting de SAPIEN Technologies y formador de ScriptingTraining.com. Póngase en contacto con Don a través de su sitio web en ScriptingAnswers.com.

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