Webinar sobre «Ciclo de vida de una solución SharePoint»

Muy buenas tardes a todos,

Quería compartir con vosotros un enlace a un webinar que pude presenciar la pasada semana y que me parece de un interés capital para todas las personas que profesionalmente nos dedicamos a desarrollar sobre SharePoint. Dicho webinar estuvo dirigido por los MVPs de Encamina Alberto Díaz, Santiago Porras y Adrián Díaz, y nos estuvieron desvelando algunos de los aspectos más importantes a tener en cuenta durante el ciclo de vida de un proyecto de SharePoint y nos contaron los retos que se presentan y buenas prácticas en las distintas etapas de los mismos. Como os decía, algo capital para todos los que nos dedicamos al desarrollo de proyectos sobre SharePoint.

En el webinar hablaron de distintas etapas: Gestión de requisitos, Arquitectura de la solución, Desarrollo, Diseño, Construir y empaquetar, Calidad, Testing, Despliegue y Operaciones.

Simplemente os dejaré algunos consejos y «buenas prácticas» que he sacado del webinar.

  • El primer aspecto cuando estamos en la fase de requisitos es que hay que tener claro que estamos desarrollando sobre SharePoint, puede parecer algo muy obvio, pero todo el mundo implicado en el proyecto tiene que conocer el producto y lo que nos ofrece.
  • No se puede cambiar el producto y es importante, siempre que sea posible usar lo estándar y solo extenderlo en el caso de que nuestros requerimientos lo necesiten.
  • Usar patrones y buenas prácticas de desarrollo como haríamos para cualquier otro proyecto, porque en ese aspecto SharePoint no es diferente, se puede hacer sin ningún problema.
  • Usar una herramienta de control de código fuente.
  • Estandarizar los entornos de desarrollo por medio de herramientas tipo SPInstaller y conocer los requisitos de desarrollo y tenerlos en cuenta para todo el equipo de desarrollo.
  • Con respecto al diseño, hay que procurar homogeneizar el look & feel de páginas, los elementos y el comportamiento de los mismos dentro de nuestro proyecto. Tener una comunicación fluida y proactiva entre los equipos de desarrollo y diseñadores y algo muy importante, tratar los fallos de UX como defectos y no como mejoras en nuestros proyectos para evitar que caigan en el olvido.
  • Es importante hacer CodeReviews periódicas en las que se analice el código y se intente mejorar el mismo.
  • Sobre los desarrollos en SharePoint, se pueden y deben hacer Test unitarios. Evidentemente, habrá aspectos que no se pueden probar, como los elementos de la API, pero debemos testear la lógica de negocio de nuestra aplicación.
  • Establecer un proceso de despliegue de nuestras soluciones, que sea conocido y que por medio de PowerShell incluya también parametrizaciones, configuración y que todo quede registrado para poder hacer seguimiento. No usar SharePoint Designer para hacer modificaciones, o si se hace, convertirlo lo antes posible en un artefacto o elemento que pueda ser desplegable.

Os dejo el enlace del webinar que desde Encamina han dejado en su canal de Youtube y os recomiendo a todos que lo veáis porque os va a dar información de mucha utilidad.

Enlace al webinar de Ciclo de vida de una solución

Un saludo a todos. Nos vemos en breve con mas temas de interés sobre todo lo relacionado con Azure, SharePoint y Office 365 por el blog.

SPSD: SharePoint Solution Deployer. Script para hacer deploy de soluciones en SharePoint

Muy buenas a todos,

Hace unos meses os enseñaba mi primer script powershell con el que se podía hacer deploy de soluciones en diferentes WebApplications. Aunque el script cumplía sus funciones y para usarlo en los entornos de desarrollo y pruebas ha funcionado con buenos resultados, a la hora de usarlo en un entorno de producción, necesitábamos más información y poder hacer un mejor seguimiento del deploy y el resultado del mismo. Aquí os dejo un enlace al post donde se encuentra el script que os comentaba.

Script de PowerShell: Despliegue de soluciones automáticamente

Lo que hoy os quiero enseñar, aunque seguro que muchos ya lo conocéis, es SPSD: SharePoint Solution Deployer, que como en la misma web del proyecto indica:

SharePoint Solution Deployer helps you to deploy SharePoint solution packages (.wsp) to multiple SharePoint environments. It deploys, retracts and upgrades one or more WSPs and can be extended to perform additional custom tasks in PowerShell before or afterwards. Unlike the most of the available scripts on the net, it performs all necessary prerequisite checks and post-deployment actions on all servers in the farm to assure the deployment runs smooth.

Aquí os dejo el enlace a la web del proyecto en CodePlex, donde lo podéis descarga. Es muy sencillo de usar y muy completo, tiene un fichero de configuración muy potente en el que puedes configurar todo el aspecto del deploy de las soluciones. Toda la documentación es muy completa y puedes ver todas las opciones que tiene.

http://spsd.codeplex.com/

Como podréis ver en la página principal del proyecto con el fichero de configuración se podrán configurar aspectos tan diversos como:

  • TimeOut de espera del script, versión mínima de SharePoint, licencia mínima de SharePoint, etc.
  • Tipo de deploy que se va a realizar
  • Acciones a llevar a cabo después del deploy: reinicio de servicios, ejecutar warmup, etc.
  • Establecer que donde se debe hacer el deploy de cada solución

Si no lo conocíais ya, espero que os sea útil, yo estoy empezando a usarlo como script para el deploy de soluciones y estoy teniendo unos resultados muy buenos.

Un saludo a todos

Script de PowerShell: Despliegue de soluciones automáticamente

Hola a todos,

Tenía muchas ganas de escribir un post relacionado con PowerShell. Reconozco que cuando empecé con SharePoint, era oír hablar de PowerShell y echarme a temblar. Si me costaba enterarme y empezar a manejar la API de SharePoint, trabajar con PowerShell ya mejor ni pensarlo.

Pero eso ha ido cambiando a medida que he ido conociendo SharePoint, al final cuando le empiezas a dedicar un poco de tiempo, te das cuenta de lo que se puede hacer con PowerShell. Y llegamos a hoy, quiero compartir con vosotros mi primer Script de PowerShell, que nace a partir de una necesidad y con un fin concreto, nada de pequeños Scripts para aprender a usar esta potente herramienta y «jugar» un poco.

Os voy a contar primero lo que necesitaba y lo que quería hacer y luego os enseño el código. El objetivo del Script era el siguiente:

  • Crear un Script que permita automáticamente desplegar las soluciones en los distintos entornos de que disponemos en todas las WebApplication.
  • El Script debe dejar activadas las características de la solución en los distintos sitios en los que se instale.
  • Dejar un registro de las tareas que se han realizado.

El Script accederá a una carpeta cuya ruta será indicada como parámetro. Dicha carpeta tendrá una estructura como la que vamos a ver a continuación.

Sin título.002

El contenido como podéis ver es muy sencillo:

  • Contendrá una subcarpeta llamada «logs» donde se guardarán los resultados de cada ejecución del script.
  • Por cada WebApplication habrá una carpeta con la siguiente estructura <urlservidor>-<puerto>, donde se encontrarán los archivos .wsp que se quieren desplegar en cada uno de los WebApplication.

el código del script es el que os muestro a continuación

param([string]$path="")


Function GetFileFolder([string]$path)
{
   
    if(Test-Path -Path $path -PathType container)
    {
        return Get-ChildItem $path
    }
    else
    { 
        throw [System.IO.FileNotFoundException] "$path not found or it isn't a folder."
    }
}

Function DisableFeaturesBySolution([string]$solutionid)
{
    $features = Get-SPFeature | Where {$_.solutionid -eq $solutionToInstall.id}
            
    foreach($feature in $features)
    {
        Disable-SPFeature -identity $feature.id -URL "http://$webapplication" -Confirm:$false -Force
    }    
}

Function EnableFeaturesBySolution([string]$solutionid)
{
    $features = Get-SPFeature | Where {$_.solutionid -eq $solutionToInstall.id}
            
    foreach($feature in $features)
    {
        enable-SPFeature -identity $feature.id -URL "http://$webapplication" -Confirm:$false -Force
        $featureName = $feature.DisplayName
        Write-Host "---> $featureName enabled successfully" -foregroundcolor "Blue"
    }
}

Function InstallWspSolutions([string]$webapplication, [string]$solutionPath, [array]$solutions)
{
    $count = 0
    Add-PSSnapIn Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
    
    foreach($solution in $solutions)
    {    
        if($solution -ne 0)
        {        
            $solutionToInstall = Get-SPSolution | Where {$_.Name -eq $solution.Name}
            
            if($solutionToInstall -eq $null)
            { 
                Add-SPSolution "$solutionPath\$solution"
            }
            else
            {
                DisableFeaturesBySolution $solutionToInstall.id
            }

            Install-SPSolution -Identity $solution.Name -WebApplication "http://$webapplication" -GACDeployment -Force
            
            Write-Host "-> $solution installed successfully in $webapplication" -foregroundcolor "Blue"
            
            EnableFeaturesBySolution $solutionToInstall.id
            
            $count = $count + 1
        }
    }

    Write-Host "$count solutions successfully installed in $webapplication" -foregroundcolor "Blue"
    
    return $count
}

Function GetSolutions([string]$path)
{
    $subElements = Get-ChildItem $path
    $solutionPathElement = @(0)
    
    foreach($file in $subElements)
    {
        if(Test-Path -Path "$path\$file" -PathType Leaf)
        {
            $solutionPathElement += $file
        }
    }
    
    return $solutionPathElement
}

Function CreateLogFile([string]$path)
{
    $filename = Get-Date -uformat "%Y-%m-%dT%H-%MZ"
    New-Item "$path\logs\$filename.txt" -type file
}

Function AddLogLine([string]$logfile, [string]$line)
{
    Add-Content $logfile $line
}

Function SolutionsInstallation([string]$path)
{
    try
    {
        $subFolderArray = GetFileFolder $path
        
        $logfile = CreateLogFile $path
        $now = Get-Date
        
        AddLogLine $logfile "----------------------------------------------------------------------"
        AddLogLine $logfile " Log File: $logfile "
        AddLogLine $logfile " Server Deployment Action Started at $now "
        AddLogLine $logfile "----------------------------------------------------------------------"
        
        foreach($file in $subFolderArray)
        {
            if((Test-Path -Path "$path\$file" -PathType container) -and ($file.Name -ne "logs"))
            {
                $webapplication = $file.Name.Replace("-",":")
       
                $solutions = GetSolutions "$path\$file"

                $solutionCount = $solutions.Count
                
                if($solutionCount -gt 0)
                {
                    AddLogLine $logfile "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>"
                    AddLogLine $logfile "WebApplication: $webapplication"
                
                    Write-Host "Installing Solutions in $webapplication ..." -foregroundcolor "Green"
                    $solutionInstalled = InstallWspSolutions $webapplication "$path\$file" $solutions
                    
                    AddLogLine $logfile "Solutions Successfully Installed: $solutionInstalled Solutions"
                    AddLogLine $logfile "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>"
                }
                else
                {
                    Write-Host "No solutions to install in $webapplication ..." -foregroundcolor "Green"
                    
                    AddLogLine $logfile "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>"
                    AddLogLine $logfile "WebApplication: $webapplication"
                    AddLogLine $logfile "Solutions Successfully Installed: 0 Solutions"
                    AddLogLine $logfile "<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>"
                }
            }
        }
    }
    catch
    {
        Write-Host $_.Exception.Message -foregroundcolor "Red"
    }
}


if($path -eq "")
{
    Write-Host "You need to give the path when the solutions are stored" -foregroundcolor "Red"
}    
else
{
    SolutionsInstallation $path 
}

Las dos funciones principales del script son la función «SolutionsInstallation» y la función «InstallWspSolutions».

  • La primera de ellas es la función principal del script: inicia el log que se creará, va recorriendo las subcarpetas de los diferentes WebApplication, comprueba si hay soluciones para desplegar en cada carpeta y si es así llama a la función InstallWspSolutions
  • La segunda función es la que hace el despliegue propiamente dicho. Lo que hace esta función es comprobar en primer lugar si la solución existe ya; en caso de que no, la añade, y si existe, desactiva todas las características de la solución existente. Después, hace la implementación de la solución y al final vuelve a activar las características de la misma.

Vamos a ver ahora los resultados que nos da el script cuando lo ejecutamos. La primera nos muestra lo que el script saca por pantalla. La segunda es una imagen del log que genera el script

Sin título.001

Sin título.003

Y bueno hasta aquí mi primer script con PowerShell, por supuesto, podéis disponer del Script cuando queráis. La forma de la que espero que se utilice es crear una tarea dentro del Task Scheduler del servidor que ejecute el Script. Que éste acceda a la carpeta correspondiente, busque si hay .wsp y los instale y que esta tarea se programe para que los despliegues se hagan automáticamente.

Por supuesto el script será muy mejorable. Por lo pronto, yo como mejoras, me gustaría poder controlar si una solución ha tenido algún error y que quede recogido en el log, que una solución o característica no han quedado correctamente activados.

¿Que más se os ocurre para mejorarlo?, ¿De qué otras formas podría hacer ese funcionamiento que pretendo?

Estoy abierto a cualquier sugerencia.

Saludos a todos