Mi experiencia en PowerShell

Como dijo Martín Salías en la VAN de AltNet Hispano acerca de automatización (mas información y video aquí):

“Antes de hacer algo por cuarta vez, automatízalo”

Fue ayer que me encontraba en uno de estos momentos:

  • actualizando la carpeta “SharedLibs” de uno de mis proyectos mediante..
  • WinMerge comparaba cuales de esas dlls necesitaba actualizar..
  • y ese juego de DLLS las había descomprimido de ..
  • un zip que había bajado del teamcity de un proyecto

Era la 4 vez que hacía todo este proceso manualmente, así que me pareció simpático, práctico y cómodo tener un proceso batch dentro de esa misma carpeta, y tome el consejo de Martín.

En este post no voy a hablar tanto del proceso en si, mas bien de PowerShell que es la tecnología que use para crear el script. Quiero destacar que es la primera vez que la uso y se que no la estoy usando adecuadamente, así que sepan disculparme, y si es posible envíenme la mejora.

Qué es PowerShell

Según Wikipedia:

Windows PowerShell es una interfaz de consola (CLI) con posibilidad de escritura y conjunción de comandos por medio de guiones (scripts en inglés). Es mucho más rica e interactiva que sus predecesores, desde DOS hasta Windows XP. Esta interfaz de consola está diseñada para su uso por parte de administradores de sistemas, con el propósito de automatizar tareas o realizarlas de forma más controlada.

Las características que destaco yo sobre sus antecesores, son:

  • Sintaxis mucho más rica y evolucionada que sus predecesores, las estructuras como condicionales y bucles se asemejan mucho a un lenguaje orientado a objetos moderno.
  • Poder acceder directamente a las clases del framework de .Net.
  • Poder interactuar con componentes del sistema operativo, y con programas tales como Active Directory, WMI, Sql Server, etc.

Tooling

En la primer búsqueda que hice en google sobre algún editor de scripts, me di con PowerGUI que es muy bueno y free, permite hacer cosas como depurar los scripts, poner puntos de interrupción, inspeccionar variables etc. Además de eso tiene un muy buen intellisence, cabe mencionar también que en la consola de PowerShell hay una especie de intellisence pero el de PowerGUI es mejor.

PowerShell para programadores en C#

Si sos programador de C#, este es el ABC:

  • Las líneas no terminan con “;”
  • Las variables siempre empiezan con el símbolo pesos “$” y no hace falta declararlas. Esto último es casi obligatorio en todos los lenguajes interpretados, pero lo digo por las dudas.
  • Para crear una instancia de un objeto se utiliza new-object en lugar de “new”.
  • Para llamar a una método estático se utiliza la siguiente forma: [System.IO.File]::ReadAllText(…) . Este es el único momento en que el nombre de clase y namespace se escriben de esa forma.
  • Los condicionales (IF-Else) se escriben de igual forma, o muy similar, lo mismo sucede con las estructuras de bucles.
  • Siendo programador de C# se puede caer en el vicio de querer usar para todo las clases del BCL. PERO parece que a la gente que sabe de PowerShell no le gusta mucho eso, ya que powershell tiene buenos comandos para muchos tipos de tareas. Ósea que el consejo es primero trata de hacerlo “a la powershell” si no te alcanzan los comandos, busca la forma con cosas de la BCL.

Mi script

Bueno acá les dejo mi script por si a alguien le sirve:

$assembliesFolder = $PWD.Path + ""
$tempFolder = "c:tempmitemp"
$zipFile = $tempFolder + "lastVersionOfXYZ.zip"
[System.IO.Directory]::CreateDirectory($tempFolder)

#Descargar el zip
$networkCredentials = new-object System.Net.NetworkCredential("my-user", "my-pass")
$webClient = new-object System.Net.WebClient
$webClient.Credentials = $networkCredentials
$url = "http://my-domain/httpAuth/downloadArtifacts.html?buildTypeId=bt8&buildId=lastFinished"
$webClient.DownloadFile($url, $zipFile)

#Descomprimir
$sh = new-object -com shell.application
$zipfolder = $sh.NameSpace($zipFile)
$unzipIn = $sh.NameSpace($tempFolder)
$unzipIn.Copyhere($zipfolder.items())

#Copiar solo los archivos que ya existen en el destino
foreach($file in [System.IO.Directory]::GetFiles($tempFolder))
{
    if ([System.IO.File]::Exists($assembliesFolder + [System.IO.Path]::GetFileName($file)))
    {
        Copy-Item $file $assembliesFolder
    }
}
#Eliminar los archivos temporales
$allFilesToRemove = $tempFolder + "*"
del $allFilesToRemove

Algunos comentarios:

  • Si el lugar desde donde descargas el zip, no requiere autenticación, hay que eliminar la parte de credentials.
  • La url que muestro es un pattern standard de TeamCity para descargar un zip con todos los artefactos de la última compilación exitosa. La única parte que debes cambiar es el valor del buildTypeId. Este código lo podes obtener navegando por la página del proyecto en TC.
  • En el proceso para descomprimir, estoy usando algo raro lo cual con mi poca experiencia ni si quiera sabría definir que es. Tiene algo feo que hace que se muestre una ventana de windows mientras descomprime. Se que existen librerías alternativas pero requieren tener que instalarlas en cada powershell de cada maquina. Desconozco si existe alguna forma de hacer que no aparezca dicha ventana. También desconozco si existe otra cosa nativa de powershell para hacerlo.
  • Estoy 100% seguro de que el bloque de código en “Copiar solo los archivos que existen en el destino” se puede hacer con comandos nativos de PowerShell, pero después de estar un rato renegando, me di por vencido. Debería ser algo como el viejo xcopy … –u

blog comments powered by Disqus
  • Categories

  • Archives