Gestion des mises à niveau des solutions en bac à sable

Corps :

Les solutions en bac à sable constituent une fonctionnalité formidable sur la plateforme SharePoint 2010.  Toutefois, ces solutions étant déployées à différents emplacements dans votre batterie de serveurs ou dans votre collection de sites, se pose la question de savoir comment les gérer.

Nous fournissons un script PowerShell qui vous aide dans cette tâche.  Il est assez simple, mais peut être étendu en fonction des outils que vous utilisez déjà pour gérer vos batteries de serveurs et vos collections de sites.

Permettez-moi de décrire ce que fait ce script : 

À chaque solution en bac à sable déployée est associé un ID de solution.  Cette solution comporte une ou plusieurs fonctionnalités dotées d’un ID de fonctionnalité et d’un numéro de version.   Pour un ID de solution donné, ce script passe en revue la totalité de votre batterie de serveurs ou de votre collection de sites et génère un journal vous indiquant tous les emplacements auxquels se trouve cette solution.  Ensuite, il examine chaque fonctionnalité dans la solution et ajoute une entrée de journal indiquant la version déployée de cette fonctionnalité.  En outre, il peut effectuer la mise à niveau si une nouvelle version de la solution est fournie.  Il s’agit d’un indicateur afin que le script puisse effectuer la mise à niveau ou être simplement utilisé pour la collecte d’informations sur la solution.

Le script prend les paramètres suivants :

·         Chemin d’accès et nom de la solution (fichier .wsp) à mettre à niveau

·         Paramètre de commutateur indiquant si la mise à niveau doit être réalisée

Autorisations :

·         Le script suppose que la personne qui l’exécute est l’administrateur local et qu’elle est autorisée à effectuer les actions de mise à niveau.

·         Les niveaux d’autorisation sont modifiés afin que l’administrateur bénéficie d’un contrôle total.

·         Au terme de la mise à niveau, les paramètres d’origine des autorisations sont restaurés.

Le format du journal est le suivant :

·         Détails sur le chemin d’accès et sur le nom de la solution en cours d’examen, notamment l’ID de solution.

·         Détails sur chaque collection de sites examinée.

·         Pour chaque collection de sites

o   Informations indiquant si une solution correspondante a été trouvée.

o   Si tel est le cas, détails sur le fichier de solution en cours de suppression afin qu’il puisse être remplacé par la nouvelle version.

o   Si la mise à niveau est réalisée, détails sur l’issue de l’opération (réussite ou échec).

·         Un récapitulatif comprenant les informations suivantes :

o   Nombre de collections de sites examinées.

o   Si la mise à niveau n’est pas réalisée, une liste récapitulative des sites nécessitant une mise à niveau, ainsi que des détails sur la version actuelle de chaque fonctionnalité (ID) dans la solution.

o   Si la mise à niveau est réalisée, les informations sur la fonctionnalité et la version, accompagnées des détails relatifs à la réussite de la mise à niveau, à la réussite de la nouvelle installation ou à la non-modification de la fonctionnalité du fait qu’il s’agit déjà d’une fonctionnalité actuelle.

Voici quelques éléments à prendre en compte :

La plateforme SharePoint 2010 ne prend en charge la mise à niveau d’une solution que si les noms de fichier de solution sont différents.  S’ils sont identiques, vous obtenez une erreur indiquant que la solution est déjà active.  Lorsque vous mettez à niveau une solution, l’ID de solution est utilisé pour la recherche des versions existantes de cette solution et, ensuite, pour l’examen des détails de la version.  La mise à niveau constitue uniquement à passer à une nouvelle version.  Elle ne rétablit pas une ancienne version.  En outre, si les versions sont identiques, elle ne réalise aucune opération.

Nous espérons que ce script vous aide à gérer les solutions que vous déployez et qu’il facilite sensiblement les mises à niveau.

# SharePoint DLL

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

 

#Cmdlet Install

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

 

#Log file definition

$intro = "User Solution Upgrader v1.0 - Log File"

$date = (Get-Date).ToString('yyyyMMdd')

 

Set-Variable -Name ForReading -value 1 -Option Constant

Set-Variable -Name ForWriting -value 2 -Option Constant

Set-Variable -Name ForAppending -value 8 -Option Constant

 

#Assume that the current "Domain\User" is the box admin entitled to perform the reconaissance and upgrade actions.

$admin  = $env:UserDomain + "\" + $env:UserName

if ($env:UserDomain -eq $null)

{             

                $admin = $admin.substring(1)

}

 

# Get the script's parent folder. This is where the log file will be written.

$logFolder = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

$getACL = Get-Acl $logFolder

$access = $getACL.Access | Where { $_.IdentityReference -eq $admin }

if ($access -eq $null -or

    ($access.FileSystemRights -ne [System.Security.AccessControl.FileSystemRights]::FullControl -and

     ($access.FileSystemRights -ne [System.Security.AccessControl.FileSystemRights]::Write -and

      $access.FileSystemRights -ne [System.Security.AccessControl.FileSystemRights]::CreateFiles)))

{

                $logFolder = $env:userprofile

}

 

# Add the log file name to the path.

$logFileFullPath = Join-Path $logFolder "usersolutionupgrader-$date.txt"

 

# Open file

$fo = New-Object -com Scripting.FileSystemObject

$f = $fo.OpenTextFile($logFileFullPath, $ForAppending, $true)

 

if ($f -eq $null)

{

                $logFolder = $env:userprofile

                $logFileFullPath = Join-Path $logFolder "usersolutionupgrader-$date.txt"

                $f = $fo.OpenTextFile($logFileFullPath, $ForAppending, $true)

}

 

#Confirm log file on screen

Write-Host ("Log Path: " + $logFileFullPath)

 

#Write intro line

$f.WriteLine()

$f.WriteLine($intro)

 

function WriteLog

{

                $dt = Get-Date

                $logMsg = $dt.ToShortDateString() + "  " + $dt.ToShortTimeString() + "`t" + $args[0]

                $f.WriteLine($logMsg)

                Write-Output($logMsg)  #Turn this on when you need console output

}

 

function exitScript()

{

                if ($f -ne $null)

                {

                                $f.Close()

                }

                Write-Host "Exiting script due to error."

                exit

}

 

WriteLog ("Current user (admin):   $admin")

 

#solution details

$solFile = ""

$targetSolutionId = ""

$upgrade = $false

$myError = $null

 

$haveCurrentFeatures = $false

$haveNewFeatures  = $false

$numSites = 0

$oldFeatures = @{}

$newFeatures = @{}

$solSites = New-Object System.Collections.ArrayList

$solFailSites = New-Object System.Collections.ArrayList

 

#Parse the commandline parameters

if (($args -eq $null) -or ($args.Count -lt 2))

{

                WriteLog("Error: This script has been called without enough parameters. Listing your parameters below:")

                WriteLog($args)

                if ($f -ne $null)

                {

                                $f.Close()

                }

                exitScript

}

else

{

                $badParameters = $false

                foreach ($arg in $args)

                {

                                switch ($arg)

                                {

                                                "-upgrade"  {$upgrade = $true}

                                                "-path" {[void] $foreach.MoveNext(); $solFile = $foreach.Current}

                                                default {$badParameters = $true}

                                }

                }

 

                if ($badParameters -eq $true)

                {

                                WriteLog("You passed in a bad parameter.")

                                exitScript

                }                             

 

                #Validate parameters

                $extension = [IO.Path]::GetExtension($solFile)

                if (($extension -eq $null) -or ($extension -ne ".wsp") -or (!(Test-Path $solFile)))

                {

                                WriteLog("Error: The solution file name is not of WSP format or is an invalid file.")

                                exitScript

                }

 

                #Confirm parameter values captured

                $fileName = Split-Path $solFile -Leaf

                WriteLog("Solution Path is: `t" + $solFile)

                WriteLog("Solution Name is: `t" + $fileName)

                if ($upgrade)

                {

                                WriteLog "The tool will attempt to perform UPGRADE on the site collections"

                }

                WriteLog ""

}

 

#Get solution ID from given WSP

$tempPath = Join-Path $env:temp "upgrader" | Join-Path -ChildPath $fileName

$shell = New-Object -ComObject "Shell.Application" -ErrorAction:SilentlyContinue -ErrorVariable myError

if ($myError -ne $null)

{

                WriteLog("FAILED to create the Shell.Application object.")

                WriteLog("Error: " + $myError)

                $myError = $null

}

 

[IO.Directory]::CreateDirectory($tempPath)  | Out-Null

$tempFolder = $shell.NameSpace($tempPath)

$tempFolder.CopyHere($solFile)

 

#Take the file name ("yourfile.wsp") from the original path

$tempSolPath = Join-Path $tempPath $fileName

 

if (!(Test-Path $tempSolPath))

{

                WriteLog "Error: Failed to copy WSP file to temp location."

                exitScript

}

 

#Rename the WSP file to have CAB extension in order to facilitate CAB extraction

$cabFileName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + ".cab"

 

Rename-Item $tempSolPath $cabFileName

$cabPath = Join-Path $tempPath $cabFileName

 

$sourceWsp = $shell.NameSpace($cabPath).items()

$tempFolder.CopyHere($sourceWsp)

$manifestPath = Join-Path $tempPath "manifest.xml"

[xml]$manifest = Get-Content $manifestPath

$targetSolutionId = $manifest.Solution.SolutionId

 

#Validate Solution GUID

[Guid]$testGuid = "B80D56EC-5899-459d-83B4-1AE0BB8418E4"

if (($targetSolutionId -eq $null) -or ($targetSolutionId.Length -lt 36) -or

    ([System.ComponentModel.TypeDescriptor]::GetConverter($testGuid).ConvertFromString($targetSolutionId) -eq $null))

{

                WriteLog("Error: Target solution ID is invalid: " + $stringSolutionId)

                exitScript

}

 

WriteLog("Extracted solution ID: $targetSolutionId from manifest.xml")

WriteLog("")

 

#Now delete temp folder.

Remove-Item $tempPath\*

Remove-Item $tempPath

 

#Go through Content DBs

WriteLog ("Looking for Solution Id: " + $targetSolutionId + " in all Content Databases`n")

$dbs = Get-SPContentDatabase

 

foreach ($contentdb in $dbs)

{

                #Web App Level

                $webAppUrl = $contentdb.WebApplication.Url

 

                #Get WebApp

                $webApp = Get-SPWebApplication -Identity $webAppUrl

 

                $policy = $webApp.Policies[$admin]

                $policyAdded = $false

                $roleAdded = $false

 

                #If the admin doesn't have Full Control, it will be granted as follows:

                if ($policy -eq $null)

                {

                                $policy = $webApp.Policies.Add($admin, "") 

                                $webAppModified = $true

                                $policyAdded = $true

                                WriteLog "Added a policy entry for user '$admin'."

                }

 

                $fullRole = $webApp.PolicyRoles.GetSpecialRole([Microsoft.SharePoint.Administration.SPPolicyRoleType]::FullControl)

                if ($policy.PolicyRoleBindings[$fullRole] -eq $null)

                {

                                $policy.PolicyRoleBindings.Add($fullRole) 

                                $webAppModified = $true

                                $roleAdded = $true

                                WriteLog "Full Control added for '$admin' to Web Application '$webAppUrl'"

                }

 

                if ($webAppModified)

                {

                                $webApp.Update()

                                $webAppModified = $false

                }

 

                #Done. Have Full Control

                WriteLog ("Entering Web Application '$webAppUrl'.`n")

                Get-SPSite -WebApplication $webApp -Limit ALL | % {

                                $site = $_

                                $solution = $null

                                $foundSolution = $false

 

                                #Scan for solution here

                                Get-SPUserSolution -Site $_ | Where { $_.Status -eq [Microsoft.Sharepoint.SPUserSolutionStatus]::Activated -and $_.SolutionId -eq $targetSolutionId } | % {

                                                if ($foundSolution -eq $false)

                                                {

                                                                $foundSolution = $true

                                                                $solution = $_

 

                                                                if ($haveCurrentFeatures -eq $false)

                                                                {                             

                                                                                Get-SPFeature -Sandboxed -Site $site | Where { $_.SolutionId -eq $targetSolutionId } | % {$oldFeatures.Add($_.Id, $_)}

                                                                                $haveCurrentFeatures = $true

                                                                }

 

                                                                if ($upgrade -eq $false)

                                                                {             

                                                                                $solSites.Add($site.Url)  | Out-Null         

                                                                }

                                                                $solutionHash = $_.Signature

                                                                WriteLog ("Found site collection: " + $site.Url)

                                                }

                                }

                                $numSites ++

                               

                                #DoUpgrade here

                                if ($upgrade -and $foundSolution)

                                {

                                                $successAdd = $false

                                                WriteLog ("Uploading new solution file as: $fileName")

 

                                                #Add + Upgrade solution

                                                $myError = $null

                                                Add-SPUserSolution -LiteralPath $solFile -Site $site -ErrorAction:SilentlyContinue -ErrorVariable myError -Confirm:$false

                                                if ($myError -ne $null)

                                                {

                                                                WriteLog("Site collection '" + $site.Url + "' FAILED to upload the new solution.")

                                                                WriteLog("Error: " + $myError)

                                                                $myError = $null

                                                }

                                                else

                                                {

                                                                $successAdd = $true

                                                }

                                               

                                                $addedSolution = Get-SPUserSolution -Identity $fileName -Site $site

                                                if ($addedSolution -ne $null)

                                                {

                                                                WriteLog ("Found solution $fileName in the Solutions Gallery. Attempting to use it...")

 

                                                                #First check for already updated solution

                                                                if ($addedSolution.Signature -eq $solutionHash) 

                                                                {

                                                                                #This means we have the same version installed. Just skip it. And delete our copy!

                                                                                WriteLog ("New solution is already active on this site collection.")

               

                                                                                if ($successAdd -eq $true)

                                                                                {

                                                                                                #Remove the new solution (the dupe)

                                                                                                WriteLog ("Removing file: $fileName")

                                                                                                Remove-SPUserSolution -Identity $addedSolution -Site $site -Confirm:$false

                                                                                                if (!($solFailSites.Contains($site.Url)))

                                                                                                {

                                                                                                                $solFailSites.Add($site.Url) | Out-Null

                                                                                                }

                                                                                }

                                                                }

                                                                else

                                                                {

                                                                                #Perform upgrade

                                                                                Update-SPUserSolution -Identity $solution -Site $site -ToSolution $addedSolution -ErrorAction:SilentlyContinue -ErrorVariable myError -Confirm:$false

                                                                                if ($myError -ne $null)

                                                                                {

                                                                                                WriteLog("Site collection '" + $site.Url + "' FAILED to upgrade to the new solution.")

                                                                                                WriteLog("Error: " + $myError)

                                                                                                if (!($solFailSites.Contains($site.Url)))

                                                                                                {

                                                                                                                $solFailSites.Add($site.Url) | Out-Null

                                                                                                }

                                                                                                $myError = $null

                                                                                }

 

                                                                                if (!($solFailSites.Contains($site.Url)))

                                                                                {

                                                                                                #Upgrade succeeded

                                                                                                WriteLog("Site collection '" + $site.Url + "' has been upgraded to the new solution.")

                                                                                                WriteLog ""

                                                                                                $solSites.Add($site.Url)  | Out-Null

 

                                                                                                #Record results AFTER upgrade

                                                                                                if ($haveNewFeatures -eq $false)

                                                                                                {                             

                                                                                                                Get-SPFeature -Sandboxed -Site $site | Where { $_.SolutionId -eq $targetSolutionId } | %{$newFeatures.Add($_.Id, $_)}

                                                                                                                $haveNewFeatures = $true

                                                                                                }

                                                                                }

                                                                }

                                                }

                                                else

                                                {

                                                                if (!($solFailSites.Contains($site.Url)))

                                                                {

                                                                                $solFailSites.Add($site.Url) | Out-Null

                                                                }

                                                }

                                }

                                $site.Close();

                }             

 

                #Close permissions and webApp

                if ($roleAdded)

                {

                                $policy.PolicyRoleBindings.RemoveById($fullRole.Id)

                                $webAppModified = $true

                        WriteLog "Removed Full Control for '$admin' from Web Application '$webAppUrl'"

                }

                if ($policyAdded)

                {

                                $webApp.Policies.Remove($admin)

                                $webAppModified = $true

                                WriteLog "Removed the policy entry for user '$admin'."

                }

                if ($webAppModified)

                {

                                $webApp.Update()

                                $webAppModified = $false

                }

                WriteLog ""

                WriteLog "Done with Web Application."

                WriteLog ""

}

 

#Final tally of site collections

WriteLog("Analysis of site collection upgrades for solution ID $targetSolutionId ...")

WriteLog("We have processed a total of $numSites site collections.")

WriteLog("")

 

if ($upgrade)

{

                #Site Collection Summary

                if ($solSites.Count -eq 0)

                {

                                WriteLog("No site collections were upgraded. Refer to this log for any upgrade errors.")

                }

                else

                {

                                WriteLog("Listing site collections that have been upgraded:")

                                foreach ($siteUrl in $solSites)

                                {

                                                WriteLog($siteUrl)

                                }

                }

 

                if ($solFailSites.Count -ne 0)

                {

                                WriteLog("Listing site collections that FAILED to upgrade:")

                     ��          foreach ($siteUrl in $solFailSites)

                                {

                                                WriteLog($siteUrl)

                                }

                }

 

                #Feature Upgrade Summary

                if ($newFeatures.Count -gt 0)

                {

                                WriteLog ""

                                WriteLog "Feature upgrade summary for the New User Solution:"

                                foreach($fKey in $newFeatures.Keys)  

                                {

                                                $fDef = $oldFeatures[$fKey]

                                                $fDef2 = $newFeatures[$fKey]

                               

                                                #Feature ID and DisplayName

                                                WriteLog("Feature ID: " + $fDef2.Id + "`t DisplayName: " + $fDef2.DisplayName)

 

                                                #Feature Version

                                                if ($fDef -eq $null)

                                                {

                                                                #New feature added.

                                                                WriteLog("This feature has been newly added.`t`t`t Version " + $fDef2.Version)

                                                }

                                                else

                                                {

                                                                if ($fDef.Version -eq $fDef2.Version)

                                                                {

                                                                                WriteLog("This feature has been unchanged.`t`t`t Version " + $fDef2.Version)

                                                                }

                                                                else

                                                                {

                                                                                WriteLog("Feature went from Version " + $fDef.Version + " to Version " + $fDef2.Version)

                                                                }

                                                }                             

                               

                                                WriteLog ""

                                }

                                WriteLog ("The new solution holds a total of " + $newFeatures.Count + " feature(s).")

                }

}

else

{

                if ($solSites.Count -eq 0)

                {

                                WriteLog("No site collections have been found.")

                }

                else

                {

                                WriteLog("We have found " + $solSites.Count + " site collections, as follows (no upgrade action performed):")

                                foreach ($siteUrl in $solSites)

                                {

                                                WriteLog($siteUrl)

                                }

                }

 

                WriteLog ""

                WriteLog "Feature summary for current User Solution:"

                foreach($fKey in $oldFeatures.Keys)

                {

                                $fDef = $oldFeatures[$fKey]

                                WriteLog ("Feature DisplayName: `t" + $fDef.DisplayName)

                                WriteLog ("Feature Version: `t" + $fDef.Version)

                                WriteLog ("Feature Id: `t`t" + $fDef.Id)

                }

 

                WriteLog ""

                WriteLog ("Found a total of " + $oldFeatures.Count + " feature(s).")

                WriteLog ""

}

WriteLog ""

 

#Close the file handle.

if ($f -ne $null)

{

                $f.Close()           

}

 

Date de publication : 15/8/2010 23:30

Ce billet de blog a été traduit de l’anglais. L’article d’origine est disponible à la page Managing Upgrades on Sandbox Solutions.