viernes, 3 de abril de 2015

Could not load file or assembly Microsoft.WindowsAzure.Packaging

Luego de instalar la última actualización del Azure SDK 2.5.1 para Visual Studio 2013 ya no pude volver a publicar mi Cloud Service. El error reportado era:

Could not load file or assembly 'Microsoft.WindowsAzure.Packaging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

Error al intentar publicar mi Cloud Service

Buscando en diferentes sitios pude dar con una comentario de Wayne Kuo en StackOverflow explicando que el problema era originado por un problema en el instalador de la nueva versión del Azure SDK, y que pudieron comprobar que quitando y volviendo a instalar las Microsoft Azure Authoring Tools 2.5.1 el problema se solucionaba.
Azure Authoring Tools Installer

Las Microsoft Azure Authoring Tools 2.5.1 pueden bajarse desde:
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x64.msi
http://download.microsoft.com/download/1/E/7/1E76DD6F-66F1-47E0-A76A-3BBAAC617316/MicrosoftAzureAuthoringTools-x86.msi

En mi caso bastó con ejecutar la opción Repair del instalador de las Authoring Tools, no fue necesario hacerlo en dos pasos (desinstalar y volver a instalarlas).

Opción de reparación

Una vez finalizada la reparación de las Microsoft Azure Authoring Tools 2.5.1 pude volver a publicar mi Cloud Service normalmente.

martes, 17 de marzo de 2015

Como compilar Docker Client en Windows

Desde noviembre de 2014, cuando Ahmet Alp Balkan anunció la disponibilidad de compilar Docker Client sobre Windows, han cambiado algunas cosas.

Acá dejo los comandos que utilicé para compilar el cliente Docker sobre un Windows 8.1 usando Git for Windows, y obviamente Go, el lenguaje en el cual está programado Docker.

Requisitos


Para poder compilar Docker es necesario tener instalado previamente Git for Windows y Go.

Por default el instalador para Windows deja Go en la carpeta C:\Go, y en el ejemplo a continuación se muestra así. Si cambias la carpeta de instalación de Go entonces modifica también la carpeta del primer comando (export GOPATH="c:\go").

Procedimiento

  1. Abrir una consola de Git Bash desde el disco donde está instalado el Go. Para esto dale clic derecho sobre el icono del disco en cualquier explorador de archivos, y selecciona la opción Git Bash que agregó la instalación del Git for Windows.

  2. En la consola de Git Bash ejecuta los siguientes comandos:
# Get the Docker source
export GOPATH="c:\go"
cd $GOPATH
go get github.com/docker/docker

# Compile go-autogen
export GOPATH="$GOPATH;$GOPATH\src\github.com\docker\docker\vendor"
cd src/github.com/docker/docker
hack/make/.go-autogen

# Finally compile Docker Client
export DOCKER_CLIENTONLY=1
cd docker
go build -v

..y listo, en la carpeta $GOPATH\src\github.com\docker\docker\docker te quedó el archivo docker.exe que estabas buscando.

Consola de Git Bash

Si no queres hacer todo esto podes bajarte el Docker 1.18 compilado en Windows desde esta ubicación: https://seketman.blob.core.windows.net/docker/docker_1.18.exe... mucho mas rápido.

sábado, 14 de marzo de 2015

Microsoft Azure Cloud Service - VIP swap feature

El Cloud Service de Microsoft Azure provee la posibilidad de implementar nuestro servicio en dos entornos propios: Production y Staging, y mediante un proceso denominado VIP swap intercambiar los mismos.

Esto es grandioso porque permite implementar un servicio en el entorno de Staging, probarlo, y cuando está todo ok hacer el swap que lo dejará en Production, pero hay que tener en cuenta que este 'intercambio de implementaciones', o 'promoción del servicio en ensayo al entorno de producción', tal como se nombra en varios documentos, en verdad es solamente un intercambio de punteros (la VIP y URL de cada uno de los entornos), las implementaciones en sí no se ven modificadas por este proceso en su configuración ni estado.

Algunos puntos a tener en cuenta:
  • Cada uno de los entornos de un Cloud Service poseen tres atributos propios:
    • Su denominación: Staging o Production
    • Una virtual IP pública, o VIP.
    • ..y una URL: <nombredns>.cloudapp.net (Production), o <guid>.cloudapp.net (Staging)
  • Tanto la VIP como la URL de Staging se mantienen durante todo el ciclo de vida de la implementación mientras no sea borrada (no cambia entre deploys). 
  • Cuando una implementación es borrada de un entorno recién entonces se liberan estos valores, y al hacer una nueva implementación sobre ese entorno siempre se asigna un nuevo valor de VIP. La URL de Staging <guid>.cloudapp.net solo cambia si este proceso de borrado y nueva implementación se lleva a cabo sobre el entorno de Staging.
  • Antes de ejecutar el VIP swap debemos asegurarnos de que la configuración de la implementación en Staging sea la adecuada para pasarla a Production, ya que el proceso no altera ninguno de los valores en cuanto a cantidad de instancias de los roles, ni configuración de autoscaling.
  • Las conexiones establecidas con cada implementación al momento de ejecutar el VIP swap se mantendrán así hasta su cierre por parte del cliente o servidor, no serán canceladas por el proceso de intercambio. Solo las nuevas conexiones son dirigidas a la nueva implementación que ocupa cada entorno.
  • La opción de VIP swap aún no está disponible en el Preview Portal; para ejecutarlo tendremos que servirnos del Management Portal, o invocando la Microsoft Azure Management Service Rest API directamente, o a través del wrapper que conforman las Microsoft Azure Management Libraries, o MAML.
Sección de Management Portal - Cloud Service Dashboard
Sección del Management Portal - Cloud Service Dashboard

Bueno, sigo leyendo el Exam Ref 70-532 Developing Microsoft Azure Solutions a ver como continúa la historia de los Cloud Services.

sábado, 31 de enero de 2015

Tienda online en ASP.NET 5 sobre Docker

Intro

Entusiasmado con la posibilidad que brinda ASP.NET 5 de correr mis sitios web sobre distintas plataformas, me puse a averiguar y escribir un resumen de como levantar un sitio y correrlo sobre Docker dentro de una VM Ubuntu de Microsoft Azure... la sorpresa fue que no te lleva mas de 10 minutos, y funciona de maravillas.


Requisitos

  • Suscripción de Microsoft Azure.
  • Una VM Ubuntu Trusty 14.04 como mínimo, con el puerto 80 habilitado.
  • Estar registrado en Docker.com si queremos salvar allí la nueva imagen creada.

Contenido

  1. Preparar el contenido de la nueva imagen.
  2. Construir la imagen Docker con nuestra aplicación.
  3. Levantar un nuevo container con nuestra imagen.
  4. Salvar nuestra imagen en Docker Hub.

Docker 1. Preparar los componentes de la nueva imagen

La imagen Docker que vamos a crear para correr nuestra aplicación MVC MusicStore estará basada en la microsoft/aspnet publicado por Microsoft meses atrás que, si bien aún está en preview, sirve perfectamente para nuestro propósito.

Actualizamos nuestro Ubuntu; instalamos Docker según se explica en docs.docker.com/installation/ubuntulinux; y también nos aseguramos de contar con Git:
sudo apt-get update
sudo apt-get install docker.io
sudo apt-get install git-core

Por último clonamos en la carpeta local storeapp el proyecto MVC MusicStore de GitHub, con el comando:
git clone http://github.com/aspnet/MusicStore storeapp

Git clone
Git clone

2. Construir la imagen Docker de nuestra aplicación

Nos movemos a la carpeta storeapp/src/MusicStore y ahí creamos el archivo Dockerfile que usaremos para configurar nuestra imagen. Podes crear el archivo con nano o el editor que prefieras:
cd storeapp/src/MusicStore
nano Dockerfile

Copia el siguiente contenido dentro del archivo Dockerfile (las lineas que comienzan con # son comentarios):
# Base image
FROM microsoft/aspnet

# Copy project folder into image and restore Nuget packages
COPY . /app
WORKDIR /app
RUN ["kpm", "restore"]

# Run de web site
EXPOSE 5004
ENTRYPOINT ["k", "kestrel"]

..y creamos la imagen usando el comando:
sudo docker build -t storeapp .

Esto demora un poco, paciencia.

3. Levantar un nuevo container con nuestra imagen

Podemos ver las imágenes en nuestro sistema mediante el comando Docker images, luego levantamos nuestra imagen en un nuevo container con run, y por ultimo listamos los containers con el comando ps:
sudo docker images
sudo docker run -t -d -p 80:5004 --restart=on-failure:10 storeapp
sudo docker ps -a

Creando el Docker container con nuestra imagen

Y ya tenemos nuestra imagen corriendo en un container de Docker en nuestra VM, publicado en el puerto 80 de Ubuntu (no olvides configurar el endpoint en Azure).

4. Salvar nuestra imagen en Docker Hub

Ahora si queremos salvar la imagen en Docker Hub para utilizarla desde cualquier otra VM, o publicarla para la comunidad, podemos agregarle un tag y hacerle un push (previamente tenemos que registrarnos en Docker.com).

Tanto el image id (934e56caf9b8), como el nombre de la cuenta registrada (seketman), deben cambiarse por los valores que corresponden:
sudo docker tag 934e56caf9b8 seketman/storeapp:demo
sudo docker push seketman/storeapp:demo

Nuestro sitio funcionando

Pueden ver este sitio corriendo en soundstore.cloudapp.net

Mucha de la info mostrada se basa en el post Running ASP.NET 5 applications in Linux Containers with Docker de Ahmet Alp Balkan.

miércoles, 3 de diciembre de 2014

Universal PredicateBuilder... tunned for Azure AD Graph API queries

Las consultas a la Azure AD Graph API no admiten le sean provistos valores nulos o vacíos, y las opciones de filtro soportadas al día de hoy se limitan a and, or, eq, ge, le, Startswith, y Any.

La Microsoft Azure Active Directory Graph Client Library facilita notablemente el manejo de estas consultas desde las aplicaciones .NET, pero aún es algo incomodo la construcción dinámica de predicados, debido a lo cual recurrí para esta labor al PredicateBuilder generosamente compartido por Pete Montgomery allá por febrero del 2011.

Afortunadamente todo el entorno de Microsoft Azure está evolucionando rápidamente así que es de esperar estas limitaciones no perduren por mucho tiempo, pero comparto esta pequeña solución por si algún otro desarrollador se encuentra ante la misma situación.

Los ajustes introducidos a la versión de Pete fueron mínimos, y solo para asegurar la compatibilidad con los operadores lógicos and y or (Pete usó AndAlso, y OrElse, no soportados por la Graph API).

Consulta de usuarios

Basada en AzureADSamples/ConsoleApp-GraphAPI-DotNet

    IPagedCollection<IUser> searchResults = null;

    var predicate = GraphAPIPredicateBuilder.Create<IUser>(u => u.AccountEnabled == true);
    if (!string.IsNullOrWhiteSpace(canonicalUser.Name))
        predicate = predicate.And(u => u.UserPrincipalName.StartsWith(canonicalUser.Name));
    if (!string.IsNullOrWhiteSpace(displayname))
        predicate = predicate.And(u => u.DisplayName.StartsWith(displayname));
    if (!string.IsNullOrWhiteSpace(description))
        predicate = predicate.And(u => u.GivenName.StartsWith(givenname));

    try
    {
        ActiveDirectoryClient activeDirectoryClient =
            AzureADAuthenticationHelper.GetActiveDirectoryClientAsApplication();
        IUserCollection userCollection = activeDirectoryClient.Users;
        searchResults = userCollection.Where(predicate).ExecuteAsync().Result;
    }
    catch (Exception e)
    {
        Debug.WriteLine(string.Format("Error searching users - {0} {1}", e.Message,
            e.InnerException != null ? e.InnerException.Message : ""));
    }


GraphAPIPredicateBuilder


    /// <summary>
    /// Enables the efficient, dynamic composition of query predicates... tunned for Azure AD Graph API
    /// 
    /// Based on the work of Pete Montgomery at February 10, 2011
    /// http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/
    /// </summary>
    public static class GraphAPIPredicateBuilder
    {
        /// <summary>
        /// Creates a predicate that evaluates to true.
        /// </summary>
        public static Expression<Func<T, bool>> True<T>() { return param => true; }

        /// <summary>
        /// Creates a predicate that evaluates to false.
        /// </summary>
        public static Expression<Func<T, bool>> False<T>() { return param => false; }

        /// <summary>
        /// Creates a predicate expression from the specified lambda expression.
        /// </summary>
        public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }

        /// <summary>
        /// Combines the first predicate with the second using the logical "and".
        /// </summary>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.And);
        }

        /// <summary>
        /// Combines the first predicate with the second using the logical "andAlso".
        /// </summary>
        public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.AndAlso);
        }

        /// <summary>
        /// Combines the first predicate with the second using the logical "or".
        /// </summary>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.Or);
        }

        /// <summary>
        /// Combines the first predicate with the second using the logical "orElse".
        /// </summary>
        public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.OrElse);
        }

        /// <summary>
        /// Negates the predicate.
        /// </summary>
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
        {
            var negated = Expression.Not(expression.Body);
            return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
        }

        /// <summary>
        /// Combines the first expression with the second using the specified merge function.
        /// </summary>
        static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // zip parameters (map from parameters of second to parameters of first)
            var map = first.Parameters
                .Select((f, i) => new { f, s = second.Parameters[i] })
                .ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with the parameters in the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // create a merged lambda expression with parameters from the first expression
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        class ParameterRebinder : ExpressionVisitor
        {
            readonly Dictionary<ParameterExpression, ParameterExpression> map;

            ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
            {
                this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
            }

            public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
            {
                return new ParameterRebinder(map).Visit(exp);
            }

            protected override Expression VisitParameter(ParameterExpression p)
            {
                ParameterExpression replacement;

                if (map.TryGetValue(p, out replacement))
                {
                    p = replacement;
                }

                return base.VisitParameter(p);
            }
        }
    }


That's all folks!


jueves, 6 de noviembre de 2014

TFS - MSBuild scripts en el Custom Assembly Path?

Desde el TFS 2010 se introdujo un nuevo parámetro Custom Assembly Path (o Ruta de acceso de control de versiones a ensamblados personalizados en español... uf! que quedó largo), al Build Controller para poder especificar allí la ubicación de aquellas dll´s que queremos tener disponibles en todos nuestros Build Definitions, sin tener que estar bajándolas del TFS para cada compilación.

Custom Assembly Path en el Build Controller

Lo interesante es que cualquier archivo que se guarde en ese path del TFS, lo mismo que las carpetas y sus contenidos, es bajado automáticamente a un directorio del Build Server inmediatamente luego de cada Check In. Así podemos dejar ahí scripts de MSBuild (o lo que se nos ocurra), para ejecutar rutinas en diferentes Build Process Templates usando la activity InvokeProcess.

La carpeta en la que queda el contenido del Custom Assembly Path es:

C:\Users\%username%\AppData\Local\Temp\BuildAgent\1\

Donde username corresponde al usuario bajo el cual corre el Team Foundation Build Service. y el ultimo numero al Build Agent.

Para acceder desde un Build Process Template a esta carpeta se debe agregar un activity del tipo GetBuildEnvironment al workflow, y luego asignar su atributo Result a una variable con un scope apropiado.


GetBuildEnvironment Activity como parte del workflow

Una vez creada la variable se puede acceder a todos los atributos que expone la clase BuildEnvironment, incluido el CustomAssemblyPath. en cualquier expresión VB que esté dentro del scope especificado.

Usando la variable buildEnvironment previamente creada

Todos los links de este post quedaron apuntando a la documentación del TFS 2010 porque ese fue la versión de servidor usada en el ejemplo, pero entiendo aplica totalmente a la siguientes versiones.

lunes, 27 de octubre de 2014

Encriptando una sección del web.config para Azure

Si bien el archivo web.config no es expuesto por el IIS, la presencia de información sensible en la sección appSettings de un proyecto Cloud Service de Microsoft Azure me llevó a buscar la posibilidad de encriptarlo local, y poder usarlo sin problemas en la nube.

Y lo que encontré fue esto:

Paso 1 - Necesito un certificado


Como mi proyecto ya estaba configurado para utilizar SSL lo que hice fue reutilizar el mismo certificado autofirmado.

Si no tenes un certificado hay que agregar uno al proyecto siguiendo los pasos descritos en Configuring SSL for an application in Azure (solo los pasos Get an SSL certStep 1: Get an SSL certificate, y la parte de upload certificate del paso Upload to AzureStep 3: Upload the deployment package and certificate).

Paso 2 - Agregar PKCS12ProtectedConfigurationProvider al WebRole desde Nuget



En el caso del Cloud Service solo basta con agregar este paquete al WebRole.

Paso 3 - Configurar el proveedor de ProtectedData en el web.config


Agregar la sección configProtectedData dentro de configuration del web.config, reemplazando el thumbprintValue por el del certificado usado.
<configuration>
  <configProtectedData>
    <providers>
      <add name="ProtectedConfigurationProvider" thumbprint="thumbprintValue" type="Pkcs12ProtectedConfigurationProvider.Pkcs12ProtectedConfigurationProvider, PKCS12ProtectedConfigurationProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34da007ac91f901d"/>
    </providers>
  </configProtectedData>
  ...
</configuration>

Paso 4 - Encriptar la sección del web.config que se quiere proteger


En este caso solo buscaba encriptar la sección appSettings, pero se puede hacer lo mismo con cualquier otra sección, o varias.
aspnet_regiis -pef appSettings "C:\source\Azure\DevDay\WebRole1" -prov ProtectedConfigurationProvider
Como acertadamente anticipa Alp Arslan Eren en su blog, si ejecutando el aspnet_regiis te encontrás con un error could not load the PKCS12ProtectedConfigurationProvider assembly como me pasó a mí, siguiendo estas indicaciones se soluciona.

Y si, para armar el tutorial usé el proyecto DevDay 2014 que tan gentilmente cedió la gente de Microsoft para el concurso de AR-UY... ;-)

Paso 5 - Insertar el gacutil como parte de nuestro proyecto


Antes de poder usar la PKCS12ProtectedConfigurationProvider.dll en Azure vamos a necesitar registrarla en la GAC, y dado que los WebRoles de Azure no se están incluyendo las Microsoft SDKs tendremos que llevarnos una copia del gacutil.exe y config hacia la nube.

En mi caso levanté el Cloud Service sobre Windows Server 2012, así que me copie ambos archivos gacutil desde la carpeta C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools a una nueva carpeta Startup dentro de mi proyecto WebRole1.


Paso 6 - Nueva Startup Task para ejecutar gacutil


Al desplegar el WebRole en Azure necesitamos que se ejecute gacutil como uno de los primeros pasos. Para eso agregamos un archivo RegisterGAC.cmd (salvar este archivo de con codificación ANSI), a la carpeta Startup recientemente creada, conteniendo el comando:
Startup\gacutil.exe /nologo /i PKCS12ProtectedConfigurationProvider.dll
..y un nuevo Startup Task dentro del WebRole al archivo ServiceDefinition.csdef de la solución:
<WebRole name="WebRole1" vmsize="Small">
  <Startup>
    <Task commandLine="Startup\RegisterGAC.cmd" executionContext="elevated" taskType="simple"/>
  </Startup>
  ...
</WebRole>
Los tres archivos agregados en la carpeta Startup deben quedar marcados como Copiar en el directorio de salida: Copiar siempre.

Paso 7 - Desplegar la solucion en Azure


...y observar como la aplicación fluye gloriosa!


Fuentes:

jueves, 16 de octubre de 2014

IIS Express, HTTPS... y una URL externa

Usar el IIS Express con un sitio web creado en VS 2013 va como piña mientras te mantengas en localhost, el problema se me presentó cuando quise accederlo desde otra maquina de la red.

  1. Para empezar tuve que abrir el VS 2013 como Administrador, porque sino no me permitía cambiar la URL del proyecto.

    A continuación  cambie la URL entrando en Propiedades del proyecto, luego en Web, y ahí en el grupo de parámetros Servidores, sustituyendo localhost por el nombre publico de la maquina donde se aloja el sitio.

  2. Después tuve que crear un nuevo certificado para esa dirección usando Makecert:
    Makecert -r -pe -n CN="nombrePublico" -b 10/15/2014 -e 10/15/2017 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
    El secreto es que el certificado quede en localmachine porque ahí lo buscará el siguiente comando.

  3. Ahora falta asignar el certificado a la ip y puerto mediante netsh, ejecutando:
    netsh http add sslcert ipport=0.0.0.0:44302 certhash=certThumbprint appid={anyValidGuid}
    Podes averiguar el thumbprint, o huella digital, del certificado generado usando MMC, en el menú Archivos seleccionar la opción Agregar o quitar complementos, Certificados, y ahí Cuenta de equipo.

  4. El último paso es que nuestro equipo cliente confíe en el certificado que generamos. En mi caso usando Chrome lo que hice fue intentar acceder al sitio web alojado en el IIS Express, cuando me apareció el mensaje de el certificado no es de confianza, baje el certificado lo guarde en un archivo en mi maquina, y luego desde la configuración del Chrome lo importe a la carpeta de Entidades de certificación raíz de confianza (en este sitio se explica mucho mas detallado).

miércoles, 24 de septiembre de 2014

ACS90014 error using Active Directory Authentication Library V2

Intentando autenticar una aplicación de consola usando ADAL v2, al invocar al método AcquireToken pasando el clientId (sin clientSecret), y PromptBehavior.Always, luego del ingreso de las credenciales me devolvía el error:
ACS90014: The request body must contain the following parameter: 'client_secret or client_assertion'
Luego de buscar un rato pude encontrar que la causa era que el Application que habia creado en el Azure Active Directory era del tipo WEB APPLICATION AND/OR WEB AP cuando lo correcto, para el caso que me interesaba, era crearla del tipo NATIVE CLIENT APPLICATION.

Parte del código utilizado:

    string clientId =       ConfigurationManager.AppSettings["ClientId"];
    string clientSecret =   ConfigurationManager.AppSettings["ClientSecret"];
    string resource =       ConfigurationManager.AppSettings["ServiceRealm"];
    string authenticationUri =
                            ConfigurationManager.AppSettings["AuthBaseUri"] +
                            ConfigurationManager.AppSettings["Tenant"];

    AuthenticationContext authenticationContext =
                            new AuthenticationContext(authenticationUri, false);

    string token;
    var redirectUri = new Uri(ConfigurationManager.AppSettings["RedirectUri"]);
    try
    {
        AuthenticationResult authenticationResult = 
            authenticationContext.AcquireToken(resource, clientId, redirectUri, PromptBehavior.Always);
        token = authenticationResult.AccessToken;
        Console.WriteLine("\n Welcome " + authenticationResult.UserInfo.GivenName + " " + authenticationResult.UserInfo.FamilyName);
    }
    catch (AuthenticationException ex)
    {
        string message = ex.Message;
        if (ex.InnerException != null)
            message += "InnerException : " + ex.InnerException.Message;
        Console.WriteLine(message);
        Console.ReadKey();
        return;
    }

Basado en la publicación de Vittorio Bertocci: Active Directory Authentication Library (ADAL) v2 for .NET/Windows Store/Windows Phone–General Availability!

lunes, 11 de agosto de 2014

Invalid class [0x80041010]

Después de desinstalar el SQL Server 2005 en un Windows 7 32 bits ya no pude entrar al SQL Server Configuration Manager del SQL Server 2008... aparecía el error: "Cannot connect to WMI provider. You do not have permission or the server is unreachable".


Según explica la gente de Microsoft "This problem occurs because the WMI provider is removed when you uninstall an instance of SQL Server." (http://support.microsoft.com/kb/956013), y tal parece que las diferentes versiones de SQL Server comparten el mismo archivo de configuración WMI.

La solución pasa por volver a compilar las clases necesarias en el repositorio WMI (archivo sqlmgmproviderxpsp2up.mof), con el comando mpfcomp, para la versión del SQL Server que se desea reparar.

En mi caso (Windows 7 32 bits + SQL Server 2008), el comando fue:

mofcomp "C:\Program Files\Microsoft SQL Server\100\Shared\sqlmgmproviderxpsp2up.mof"

..y santo remedio.

viernes, 16 de noviembre de 2012

JDGui_noComments PowerShell style

Acá la versión PowerShell V2, mucho mas cómodo para mover en entornos Windows 7... y mas bonito para mostrar gracias a la Copy-ColoredAsHtml option del PowerShellPack ;-)

$fcount = 0             
$search = '^\/\* [ \d]{1,4} \*\/ '             
Get-ChildItem \source *.java -recurse |           
  Foreach-Object {             
    $c = ($_ | Get-Content)             
    if ($c -match $search) {             
      $c = $c -replace $search, ''             
      [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))             
      Write-Host $_.FullName "... updated"             
      $fcount++             
    }             
  }             
Write-Host $fcount "file(s) updated"             

Remove JD-Gui line comments

Ok, ok.. no es la gloria.. pero es mi primer script en Ruby y merecía un lugar de privilegio... and, here is JDGui_noComments!, para quitar los odiosos comentarios que JD-Gui agrega al principio de cada linea de los archivos java decompilados... algo es algo como diría mi vieja ;-)

# JDGui_noComments.rb

def treeReplace(dir, filename, search, replace)
  fcount = 0
  Dir["#{dir}/*"].each do |fd|
    if File.directory?(fd)
      fcount += treeReplace(fd, filename, search, replace)
    else
      if fd =~ filename
        text = File.read(fd)
        if text =~ search
          File.open(fd, 'w') {|f| f << text.gsub!(search, replace)}
          puts "#{fd}... updated"
          fcount += 1
        end
      end
    end
  end
  return fcount
end

# Main program
#

if __FILE__ == $0
  if ARGV.size < 1
    puts "Usage: #{$0} <dir>"
    exit
  end

  dir = ARGV[0].dup
  dir.gsub!(/\\/, "/") # MS-DOS/Microsoft Windows style path compatible
  puts treeReplace(dir, /\.java$/, /^\/\* [ \d]{1,4} \*\/ ?/, "").to_s() + " file(s) updated"
end

Mañana la versión PowerShell que terminé usando... mas sencillo para entornos Windows Seven porque ya viene como parte del SO.