Despliegues anidados de plantillas ARM automatizados con PowerShell y Azure Blob Storage

A la hora de desplegar una plantilla de Azure Resource Manager, el proceso es bastante sencillo tanto desde la línea de comandos multiplataforma como desde PowerShell. Se resume en un comando al que se le pasa el grupo de recursos y la plantilla que se quiere desplegar. Sin embargo, cuando en lugar de una única plantilla queremos hacer un despliegue de una solución más compleja compuesta por varias plantillas anidadas, esto requiere incluir algún elemento intermedio para lograrlo.

Desde una plantilla de ARM es posible invocar el despliegue de otras plantillas ARM con una única condición: deben de estar accesibles de forma pública al orquestador que las interpreta en Azure para que pueda descargársela e implementar los recursos que hemos definido. El uso de plantillas anidadas puede darse por diversos motivos, generalmente los principales suelen ser: evitar plantillas de varios miles de líneas y facilitar el trabajo de la persona o el equipo de personas que escriben dicha plantilla.

Una solución bastante común al problema es hacer uso de un repositorio público de código como lo que ofrece GitHub. Este modo es el que emplea el propio repositorio público de plantillas que Azure pone a vuestra disposición para implementar directamente o para tomar como ejemplo a la hora de crear nuestras propias plantillas. Sin embargo, en muchas ocasiones no nos interesa que nuestras plantillas estén accesibles por terceros dentro de Github. Es ahí donde entra en juego la solución que empleo yo. Probablemente no sea la mejor solución o la más completa pero es la que me facilita el trabajo con las plantillas anidadas en varios despliegues preparados para diferentes clientes. El sistema funciona de la siguiente manera.
Continue reading Despliegues anidados de plantillas ARM automatizados con PowerShell y Azure Blob Storage

Azure Notifier, un sistema de notificación basado en Logic Apps y Azure Functions

Hasta hace unas semanas, un compañero interno de Microsoft había construido una aplicación que permitía recibir por correo electrónico las novedades relacionadas con Azure de las principales fuentes de información: el blog de Azure, las actualizaciones de servicio y el contenido de Channel 9. La aplicación era un proyecto personal y tras irse de la compañía el servicio desapareció.

Debido al ritmo de evolución de los servicios de Azure, una utilidad como esta era muy práctica para tener una visión diaria de qué había nuevo, qué había cambiado y qué nuevo contenido multimedia estaba disponible para ser consumido. Es por ello que estos días de vacaciones me propuse ver si se podía montar algo rápido con los servicios PaaS de Azure y así es como me he construido mi propio servicio notificador.

Continue reading Azure Notifier, un sistema de notificación basado en Logic Apps y Azure Functions

Cómo documentar nuestros scripts de PowerShell

A la hora de documentar nuestros scripts o nuestras funciones de PowerShell es necesario que conozcamos la estructura esperada para que el comando Get-Help o el propio Host pueda extraer la información.

La estructura es bastante sencilla, se basa en una palabra clave de ayuda, SYNOPSIS, DESCRIPTION o EXAMPLE, precedida de un punto. Tras ello, un comentario asociado a dicha palabra clave que empezará en la siguiente línea. Dicha estructura debe de ir dentro de un comentario de bloque o precedida por el símbolo # en cada línea. A continuación se muestra cómo sería en ambos casos

# .[palabra clave de ayuda]
# [contenido de la ayuda relacionado con la palabra clave]
 
<#
 .[palabra clave de ayuda]
 [contenido de la ayuda relacionado con la palabra clave]
#>

El bloque de documentación puede aparecer al principio del cuerpo de la función, al final de la función o anteriormente a la palabra clave reservada function. En el caso de los scripts, ésta puede situarse al principio del fichero precedida únicamente por otros comentarios o líneas en blanco o al final del mismo salvo si es un script firmado. Un detalle importante, si el primer miembro del script es una función será necesario dejar dos líneas en blanco para evitar que sea interpretada como la documentación de la función.

Documentación autogenerada por PowerShell

Por defecto, existe un conjunto de datos que por defecto PowerShell muestra y genera de forma automática cuando llamamos al comando Get-Help. Lo más importantes son los siguientes:

  • Name : Obtenido a partir del nombre del fichero de nuestro script o del nombre de la función.
  • Syntax : Extraído de la firma de nuestro script o función.
  • Parameter List : En esta ocasión, si incluímos detalles sobre los parámetros con lo que explicaremos a continuación, la información se extraerá de ahí. Si no, a partir de la firma de nuestro script o función.

Palabras clave que podemos utilizar

Junto con lo anterior, tenemos una colección de otros parámetros que podemos añadir a nuestra documentación para hacerla más completa.

  • SYNOPSIS : una pequea descripción de la función o el script. Esta palabra sólo se puede incluir una vez.
  • DESCRIPTION : Una extensión del parámetro anterior para describir de forma detallada qué realiza la función o el script. Esta palabra sólo se puede incluir una vez.
  • PARAMETER : La descripción de cada uno de los parámetros que nuestra función o script. Es necesario incluir esta palabra clave por cada parámetro que utilicemos. El orden que utilicemos para ponerlos será el orden en el que aparezcan en la ayuda de PowerShell.
  • EXAMPLE : Diferentes ejemmplos para para ayudar al usuario a utilizar nuestra función o script. Podemos añadir tantos ejemplos como deseemos./li>
  • INPUTS : Si vamos a usar este comando en una tubería, con esta palabra clave definiremos el tipo de objeto del .Net Framework que acepta en su entrada.
  • OUTPUTS : Similar al caso anterior pero sobre el tipo de objeto de .Net Framework que devolverá al finalizar su ejecucción.
  • NOTES : Información adicional que queramos añadir sobre nuestro script o función.

No son los únicos pero sí los que probablemente utilicemos más a menudo. Si tenemos curiosidad sobre qué otros parámetros podemos utilizar podemos consultar el artículo de la documentación asociado a este tema. Para ello, desde una consola lanzaremos lo siguiente:

Get-Help about_Comment_Based_Help

O directamente en la referencia de TechNet de forma online.

Un ejemplo de ello lo podéis ver en el script que publiqué para aprovisionar nuestras imágenes de Windows Nano Server.

Utilizando los nuevos perfiles de Azure para PowerShell

Hace unos pocos días se actualizaron las herramientas de PowerShell para Azure a su última versión, la 0.8.15. Entre las novedades se encuentra una que me acaba de resultar muy útil para gestionar múltiples suscripciones de Azure desde PowerShell: los perfiles.

Nota: Si quieres actualizar tu versión de las herramientas de PowerShell o instalarlas desde cero recuerda que te resultará más fácil utilizando el script de PowerShell que creé.

Si alguna vez has intentado ejecutar un script contra múltiples suscripciones seguro que te has encontrado con las dificultades de desplegar los recursos en la suscripción correcta. Un perfil es un contenedor para agrupar una serie de suscripciones para ser usado como forma de autentificación contra los extremos de Azure. Es posible seleccionar qué perfil queremos ejecutar en cada momento de forma general para la sesión actual de PowerShell o pasándolo a cada comando con el parámetro -Profile

Podemos crear un nuevo perfil en memoria con el comando New-AzureProfile. Soporta como métodos de autenticación Azure Active Directory o Certificados. En mi caso, la segunda opción era la que buscaba. Si queréis más detalles de cómo hacerlo con Active Directory podéis consultar la documentación con Get-Help New-AzureProfile

$profile = New-AzureProfile -SubscriptionId "GUIDIdentificadorSuscripcion" -Certificate "HuellaDelCertificado"

Dicho certificado lo habremos creado previamente siguiendo las instrucciones disponibles en la documentación y lo habremos subido a través del portal de Azure. La huella del certificado lo podremos obtener de forma fácil a través de Powershell

Get-Item "Cert:\CurrentUser\My\$HuellaDelCertificado"

Una vez que tengamos nuestro perfil creado, podremos seleccionarlo para utilizarlo en nuestra sesión actual con:

Select-AzureProfile -Profile $profile

Si queremos terminar con nuestro perfil en memoria y queremos volver a emplear el que está guardado en disco podemos hacerlo con:

Select-AzureProfile -Default

En el caso de que queramos ejecutar un comando en un perfil específico podemos utilizar el parámetro -Profile para evitar tener que cambiar con Select-AzureProfile al perfil que queremos y volver después a cambiar al perfil que estábamos usando anteriormente para continuar. Por ejemplo, creando una cuenta de almacenamiento en el perfil que tengo guardado en mi variable $produccion

New-AzureStorageAccount -StorageAccountName "myAzureStorageAccount" -Location "North Europe" -Type Standard_RAGRS -Profile $produccion

Espero que os salve de algún apuro ;)

Actualización del script para mantener tu módulo de PowerShell de Azure al día

Configurando un nuevo equipo me he dado cuenta de que el script que publiqué para mantener las herramientas de PowerShell para Azure al día tenía un fallo, si no tenías ya el módulo instalado no funcionaba. Así que nada, unos pequeños cambios y ahora también es posible instalarlas por primera vez con él. Para que sea más fácil está publicado en GitHub el código.

Cómo hacer un servidor HTTP básico en Python

Probando unas cosas me he encontrado con la necesidad de tener un pequeño servidor que escuchara peticiones entrantes y realizara un acción basado en ello. Para lograrlo hay diferentes formas de hacerlo: levantar un servidor web y escribir el código con ASP.NET MVC o PHP, escribir una aplicación nativa utilizando sockets, etc.Sin embargo, quería algo rápido, sencillo y con posibilidad luego de extenderlo en el caso de que fuera necesario. Así que partiendo de esos requisitos terminé con Python y sus capacidades nativas que tiene para desplegar un servidor web.

¿Qué es necesario para ejecutar nuestro servidor?

Dentro de la rama 3.x de Python tenemos disponible dentro del módulo http una clase que nos permite crear un servidor web, su nombre es bastante descriptivo: server. Dicha clase hereda de la clase base socketserver.TCPServer implementando los elementos necesarios para responder a peticiones bajo el protocolo HTTP.

Junto con ello, necesitamos definir qué sucede cuando recibimos una petición. Para ello vamos a definir un manejador o handler. Utilizaremos como punto de partida la implementación básica que proporciona Python a través de BaseHttpRequestHandler y la extenderemos. El manejador es el encargado de analizar las cabeceras y llamar al método correcto para que procese la petición. En nuestro caso trabajaremos con peticiones del tipo HTTP GET por lo que el método que necesitaremos implementar será el do_GET, si trabajáramos con el tipo HTTP POST tendríamos que implementar el método do_POST. Al método no se le pasan argumentos, toda la información está disponible en las variables a nivel de instancia del manejador. En la documentación se pueden consultar dichas variables para saber cuáles tenemos disponibles. Si traducimos esto a código nos quedaría lo siguiente.

En primer lugar importamos las dos clases que he comentado del módulo http.server

from http.server import  BaseHTTPRequestHandler, HTTPServer

Tras ello definimos la clase que acogerá a nuestro servidor. Su constructor está sobrescrito con uno propio en el que se inicializa el servidor HTTP en el puerto 5050 y se le indica cuál va a ser el manejador que gestione las peticiones.

class http_server:
    def __init__(self):
        server = HTTPServer(('', 5050), myHandler)
        server.serve_forever()

Dicho manejador lo definimos a continuación. Dentro del mismo podemos hacer aquello que sea necesario en nuestra aplicación. En el ejemplo aparece una respuesta básica en la que se le indica al cliente que se ha procesado correctamente usando el código 200, se establecen las cabeceras HTML de la respuesta y se devuelve la información.

class myHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        # Hacer lo que queramos con la petición
        return

Si estás interesado en servir ficheros HTML puedes echarle un ojo al manejador SimpleHTTPRequestHandler que te permite construir un servidor de ficheros a partir del directorio donde se ejecute el script. En la documentación existe un ejemplo de cómo hacerlo.

Por último será definir el punto de entrada de nuestro script de Python. En este caso, será la clase que hemos definido como main y dentro de la cual instanciamos a nuestro servidor http.

class main:
    def __init__(self):
 
        self.server = http_server()
 
if __name__ == '__main__':
    m = main()

Sería posible escribir todo el código como un script en lugar de hacerlo basado en clases como hemos visto. Sin embargo, de esta forma nos permite ir añadiendo funcionalidad de una forma más sencilla y organizada.

Cómo escribir nuestros scripts de PowerShell desde Visual Studio

A la hora de escribir nuestros scripts de PowerShell el ISE es generalmente nuestro editor preferido. También hay aquellos más castizos que con el bloc de notas tienen todo lo necesario pero un editor como ISE nos permite obtener extras como el autocompletado o la depuración haciéndonos más productivos. Lo mejor del ISE es que incluso permite ser extendido añadiendo funcionalidades nuevas como las que ofrece ISESteroids.

En este caso no quiero hablar sobre extensiones que se añaden al ISE para incorporar nuevas funcionalidades sino al revés, nuevos IDEs que añaden la capacidad de desarrollar scripts de PowerShell. En este caso estoy hablando de Visual Studio, uno de los entornos de desarrollo más conocidos por los desarrolladores, y en especial de las herramientas de PowerShell para Visual Studio. Si no has usado nunca Visual Studio, puedes descargar de forma gratuita la versión de comunidad .

¿Qué nos aportan las PowerShell Tools?

De forma nativa el soporte de Visual Studio para PowerShell es limitado, queda prácticamente reducido al resaltado de sintaxis. Sin embargo, esta extensión nos permite tener características extras en diferentes partes del editor como las siguientes.

  • El editor: gracias a la integración con IntelliSense es posible el autocompletado de código, tanto de cmdlets, funciones, variables o parámetros. Por otro lado, gracias al encapsulado de código es posible mostrar y ocultar los bloques de código o comentarios.
  • Editor de Visual Studio para PowerShell
    Editor de Visual Studio para PowerShell
  • El depurador: el objetivo de la extensión es mejorar el soporte a la depuración comparado con el ISE, para ello incorpora soporte para las ventanas de variables locales, puntos de ruptura y la pila de llamadas. Gracias a la ventana de variables locales es posible tener una vista global de lo que está sucediendo en este instante y los valores que tienen cada una de ellas; también permite expandir elementos complejos para ver sus propiedades como sucede con C# por ejemplo. Una de las diferencias respecto al ISE es la capacidad de modificar los valores desde este punto. Respecto a la ventana de puntos de ruptura, esta muestra la lista de puntos disponibles dentro del proyecto. A día de hoy no existe la opción de puntos condicionales. Finalmente, la ventana de la pila de llamadas permite ver de forma visual la situación actual de la pila gracias al comando Get-PSCallStack.
  • Depuración de PowerShell en Visual Studio
    Depuración de PowerShell en Visual Studio
  • Las pruebas unitarias: si queremos utilizar un enfoque de escritura de nuestro código basado en pruebas la extensión nos permite utilizar Pester para escribir nuestras pruebas unitarias y verificar que nuestras funciones se ejecutan de forma correcta.
  • Pester - Pruebas unitarias en PowerShell
    Pester – Pruebas unitarias en PowerShell

Si te ha convencido y lo quieres probar, la extensión es totalmente gratuita y se puede descargar desde la galería de extensiones de Visual Studio: PowerShell Tools for Visual Studio 2013

Desplegando una aplicación ASP.Net vNext en un contenedor de Docker

Resumiendo hasta la fecha hemos visto lo siguiente:

  1. Instalando el motor de Docker en una máquina virtual en Azure
  2. Instalando el cliente de Docker en Windows
  3. Conexión entre el cliente y servidor de Docker desplegados de forma manual en Azure
  4. Configurando Docker para acceso a través de HTTPs

Por lo tanto, ya sólo nos queda mostrar cómo desplegar alguna aplicación en un contenedor dentro de la instancia de Docker que tenemos ejecutándose en Azure. Podríamos probar con un simple comando imprimiendo un “Hola Mundo” pero aprovechando que de versiones alfa anda el juego, vamos a desplegar una aplicación ASP.Net vNext que tras los últimos anuncios ya es posible ejecutarlo en entornos Mac OSX y Linux también.

Obteniendo nuestra aplicación de ejemplo

En primer lugar vamos a buscar la aplicación de ejemplo que queremos desplegar. Podríamos escribirla nosotros mismos desde cero o, por el contrario, optimizar el tiempo y hacer uso de alguno de los ejemplos disponibles. Si accedemos al repositorio de GitHub del equipo de ASP.Net veremos que tenemos disponible el código fuente. Dentro de los ficheros existe la carpeta de Samples donde tenemos tres ejemplos de aplicación. De todos ellos, usaremos el de HelloMVC.

Para descargarlo tenemos dos opciones, descargar el fichero .zip disponible en GitHub con todo el código fuente del repositorio o clonar el repositorio con el siguiente comando:

git clone https://github.com/aspnet/Home.git

Tanto con una opción como con la otra tendremos en nuestro ordenador una copia de los ficheros que necesitamos.

Preparando la imagen de Docker

A la hora de configurar nuestra imagen para ser ejecutada en el contenedor podemos seguir dos caminos: realizarlo de forma manual o utilizar un fichero específico, DockerFile , para que Docker lo haga por nosotros. En esta ocasión emplearemos esta segunda opción para simplificar el proceso.

Lo primero será crear nuestro fichero DockerFile. Lo podemos hacer directamente desde nuestro bloc de notas. Dentro de él iremos definiendo los pasos necesarios para desplegar nuestra aplicación.

Desde Microsoft se ha preparado una imagen base que se puede emplear como plantilla para generar las nuestras propias. Está disponible en el repositorio bajo el nombre microsoft/aspnet . Esta imagen se encarga de configurar todos los elementos necesarios para tener un entorno de ASP.Net vNext. Si tenemos curiosidad podemos ver el contenido de su DockerFile.

Por lo tanto, la primera línea de nuestro DockerFile será la siguiente.

FROM microsoft/aspnet

Tras ello, necesitaremos copiar los ficheros que forman nuestra aplicación web dentro del contenedor. A día de hoy la versión alfa del cliente de Windows para Docker no gestiona correctamente las rutas de ficheros, es necesario pararlo como un fichero comprimido. Por ello, comprimiremos nuestra carpeta HelloMVC en formato .tar con 7-Zip. El comando ADD es capaz de reconocer los ficheros .tar entre otros y descomprimirlos. Además de copiarlos, a continuación navegaremos dentro de la carpeta app para continuar con la configuración de la imagen.

Traducido lo anterior a nuestro DockerFile quedaría como lo siguiente.

ADD HelloMvc.tar /app/
WORKDIR app

Una vez que tenemos nuestra aplicación copiada necesitamos restaurar las dependencias con los paquetes de NuGet que tiene. Esto lo permite gestionar el comando kpm que se incluye con ASP.Net vNext. En nuestro DockerFile necesitaremos incorporar lo siguiente.

RUN kpm restore

Por último necesitamos exponer un extremo de nuestro contenedor a través del cual accederemos a nuestra aplicación web y configurar la image para que al ser ejecutada inicialice el servidor web de ASP.Net vNext: k. Por lo tanto, las últimas líneas de nuestro DockerFile serán las siguientes.

EXPOSE 5004
ENTRYPOINT ["k", "kestrel"]
DockerFile para nuestra aplicación ASP.Net vNext
DockerFile para nuestra aplicación ASP.Net vNext

El último paso será construir nuestra imagen. Para el comando siguiente suponemos que nuestro fichero DockerFile y HelloMVC.tar se encuentran dentro de nuestra carpeta HelloMVC.

Carpeta de ejemplo de la aplicación
Carpeta de ejemplo de la aplicación

Si no es así tendremos que adaptar el siguiente comando para que se ajuste a nuestra ruta. De todo el comando, la última parte es la que nos interesa, lo otro únicamente define los parámetros de la conexión usando HTTPs como mencionaba en el artículo anterior.

docker.exe --tlsverify --tlscacert="C:\Users\jangelfdez\Desktop\ca-public-key.pem" --tlscert="C:\Users\jangelfdez\Desktop\client-cert.pem" --tlskey="C:\Users\jangelfdez\Desktop\client-private-key.pem" -H=jangelfdez.cloudapp.net:2376 build -t myaspnetvnextapp samples\HelloMvc

Tras ello nuestra imagen comenzará a obtener los ficheros que necesita de forma automática. Esperaremos hasta que termine antes de continuar.

Creación de nuestra imagen personalizada para ASP.NET vNext
Creación de nuestra imagen personalizada para ASP.NET vNext

Una vez que haya finalizado solo nos quedará ejecutar la imagen dentro de un contenedor y nuestro sitio web estará disponible.

docker.exe --tlsverify --tlscacert="C:\Users\jangelfdez\Desktop\ca-public-key.pem" --tlscert="C:\Users\jangelfdez\Desktop\client-cert.pem" --tlskey="C:\Users\jangelfdez\Desktop\client-private-key.pem" -H=jangelfdez.cloudapp.net:2376 run -d -t -p 8080:5004 myaspnetvnextapp
Aplicación ASP.Net vNext ejecutándose en contenedor de Docker
Aplicación ASP.Net vNext ejecutándose en contenedor de Docker

Obteniendo la última versión del módulo de PowerShell de Azure

Nota: El script ha sufrido modificaciones, te recomiendo consultar la última versión en su repositorio de GitHub :)

El ritmo de evolución que tienen las soluciones en la nube es abrumador, en cuanto te despistas por un momento nuevos productos y funcionalidades están disponibles. Esto es algo que a los que estamos acostumbrados a trabajar con Azure nos pasa, sólo hay que ver los últimos cambios en el portal de actualizaciones de los diferentes servicios.

Estas nuevas funcionalidades y servicios obligan a actualizar al mismo tiempo las herramientas de gestión. En mi caso, suelo trabajar con Azure a través de PowerShell. Si vosotros queréis trabajar con lo mismo, es posible instalar el módulo de dos formas diferentes: haciendo uso del Web Platform Installer o descargándote el instalador en un fichero .msi. Aunque el WebPI es muy útil para poner a punto tu equipo con todas las herramientas necesarias si trabajas con entornos web, yo prefiero gestionar directamente la instalación del módulo de PowerShell y no tener un programa intermedio que lo haga.

La forma manual de obtener la última versión es la siguiente:

  1. Acceder al portal de GitHub del equipo de Azure donde se encuentra el repositorio de las herramientas de PowerShell
  2. Localizar la opción de ver las últimas versiones públicas
  3. Seleccionar la instalación “Windows Standalone” y descargar el fichero
  4. Lanzar la instalación desde el fichero .msi

El proceso es siempre el mismo por lo que nos da juego a que lo automaticemos con un pequeño script de PowerShell para que lo haga por nosotros. Para obtener los datos necesarios haremos uso de la API que GitHub tiene disponible de forma pública. En particular, haremos uso de la opción de listar las versiones disponibles en un repositorio.

Vamos a ver cómo realizarlo de forma automática

En primer lugar necesitaremos saber cuál es la versión que tenemos disponible del módulo en nuestro PC; en el caso de que no haya ninguna finalizaremos el script ya que no tendremos versión con la que comparar para actualizarlo o no. Otra opción sería ofrecer directamente la descarga aunque no está implementado.

# Check the actual version of the Azure Powershell module if its available
$azureModule = Get-Module -ListAvailable | Where { $_.Name -eq "Azure"}
if ($azureModule -eq $null )
{
    Write-Output "Microsoft Azure PowerShell module is not available on your computer"
    Return
}
$azureInstalledVersion = $azureModule.Version

Tras conocer cuál es la versión que tenemos instalada el siguiente paso es conocer cuál es la última que está disponible en el repositorio de GitHub. Realizaremos la consulta contra la API y en el caso de que esta no devuelva la información esperada finalizaremos la ejecución. Otra posible comprobación a añadir es que la llamada a la API se establece correctamente.

# Check the latest version of the Azure Powershell module released on GitHub
$gitHubData = Invoke-RestMethod -Method Get -Uri "https://api.github.com/repos/Azure/azure-powershell/releases" 
$latestRelease = $gitHubData | Select -First 1
 
if (![System.Version]::TryParse($latestRelease[0].name, [ref]$latestReleaseVersion) )
{
    Write-Error "Information about the latest version cannot be retrieved." -Category ConnectionError -CategoryReason "The connection to GitHub API has not been established properly and the information has not been retrieved"
    Return
}

Si ya estamos con la versión más reciente no necesitaremos continuar.

if ($azureInstalledVersion -ge $latestReleaseVersion)
{
    Write-Output "Your Microsoft Azure Powershell module version ($azureInstalledVersion) is greater or equal to the latest version ($latestReleaseVersion)."
    Return
}

Sin embargo, si tenemos una versión anterior ofreceremos la opción de actualizarse a la última descargando el fichero .msi disponible en la descripción de la release.

# Check if the user wants to update the module
Write-Output "Your Microsoft Azure Powershell module version ($azureInstalledVersion) is not the latest ($latestReleaseVersion)."
$updateModule = Read-Host "Do you want to update it? (Y/N)"
 
if ($updateModule -ne "Y")
{
    Return
}
Updating Azure PowerShell Module
Confirmación de actualización

Si aceptamos, automáticamente nos descargará el instalador y lo ejecutará por lo que nos encontraremos con la página de inicio del asistente para completar nuestra actualización:

$installerUrl = $latestRelease.body | Select-String -Pattern "\[Windows Standalone]\((http://.*)\)" | %{ ($_.Matches.Groups)[1].Value }
$savedFilePath = "$env:HOMEDRIVE$env:HOMEPATH\Downloads\azure-powershell.$($latestRelease.name).msi"
Invoke-WebRequest -Uri $installerUrl -OutFile $savedFilePath
 
Write-Output "Launching installer"
Invoke-Item $savedFilePath
Updating Azure PowerShell Module
Asistente de instalación del módulo de Azure

Si continuamos con el asistente tendremos actualizado finalmente nuestro módulo de Azure en el equipo.

Modificar la navegación inicial en Windows Phone 7…

Es posible que en alguna de las aplicaciones que desarrolles para Windows Phone 7 tengas que modificar la navegación inicial dependiendo de algún parámetro; por ejemplo, algo común es que si el usuario no ha iniciado sesión se le envíe a la página de login y si ya lo ha hecho, se envíe directamente a la página principal de la aplicación.

Buscando la mejor forma de hacerlo, o mejor dicho, la que funcionara ya que la aproximación que estaba realizando no era válida, encontré el post de Peter Torr que propone dos soluciones para controlar esta situación.

Cualquiera de los dos métodos funciona para lograr lo que se desea; sin embargo, es importante tener en cuanta algunos detalles:

  • Si posteriormente quieres emplear el NavigationService para moverte entre páginas tienes que tener en cuenta que ese código se ejecutará provocándote errores. Si solo deseas que eso se evalúe la primera vez, lo mejor es que te desuscribas del evento para evitar que vuelva a ser llamado cada vez que hagas uso de los servicios de navegación.
  • Si estás con Windows Phone 7, la vista de login se quedará en el stack de navegación. Si el usuario pulsa el botón atrás le volverá a aparecer dicha vista. Por lo tanto, es recomendable utilizar la aproximación de un elemento que se coloque por encima de la vista principal y controlar su visibilidad.
  • Si por el contrario, estás con Windows Phone 7.1, parece que Microsoft ha oído las quejas de la gente por los foros añadiendo la posibilidad de eliminar una entrada del stack de navegación con el método NavigationService.RemoveBackEntry

Así que tened en cuenta estas situaciones para evitar modificar el código que ya estaba escrito y funcionando.