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.
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
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