Gestione degli aggiornamenti nelle soluzioni in modalità sandbox

Gestione degli aggiornamenti nelle soluzioni in modalità sandbox

Corpo:

Le soluzioni in modalità sandbox sono caratteristiche importanti della piattaforma SharePoint 2010.  Poiché tuttavia vengono distribuite in diverse posizioni in una farm o in una raccolta siti, è lecito chiedersi come gestirle.

Per semplificare la gestione, viene fornito di seguito uno script di PowerShell.  Questo script è piuttosto semplice, ma può essere esteso in modo da utilizzare anche gli strumenti già in uso per la gestione delle farm e delle raccolte siti.

Viene descritta di seguito l'azione dello script: 

Ogni soluzione in modalità sandbox distribuita è associata a un ID soluzione.  Nella soluzione saranno disponibili una o più caratteristiche associate a un ID e a un numero di versione.   Dato un ID soluzione specifico, questo script esaminerà l'intera farm o raccolta siti e genererà un registro in cui vengono indicate tutte le posizioni in cui è presente la soluzione corrispondente.  Lo script esaminerà quindi ogni caratteristica all'interno della soluzione e aggiungerà una voce di registro per indicare quale versione della caratteristica è distribuita.  Può inoltre eseguire l'aggiornamento se viene fornita una nuova versione della soluzione.  Questo è un contrassegno in modo che lo script possa eseguire l'aggiornamento oppure possa essere utilizzato semplicemente per raccogliere informazioni sulla soluzione.

Nello script vengono utilizzati i parametri seguenti:

·         Percorso del file e nome della soluzione (file con estensione wsp) da aggiornare.

·         Parametro opzionale che indica se eseguire o meno l'aggiornamento.

Autorizzazioni:

·         Nello script si presuppone che l'utente che lo esegue sia un amministratore e che pertanto sia autorizzato a eseguire le operazioni di aggiornamento.

·         I livelli di autorizzazioni sono modificati in modo da concedere il controllo completo all'amministratore.

·         Dopo l'aggiornamento, vengono ripristinate le impostazioni originali delle autorizzazioni.

Il formato del registro è il seguente:

·         Dettagli sul percorso del file e sul nome della soluzione in esame, incluso l'ID soluzione.

·         Dettagli su ogni raccolta siti esaminata.

·         Per ogni raccolta siti

o   Informazioni in cui viene indicato se è stata individuata o meno una soluzione corrispondente.

o   In caso affermativo, dettagli sul file della soluzione che viene rimosso per essere sostituito con la nuova versione.

o   Se viene eseguito l'aggiornamento, informazioni sull'esito dell'operazione.

·         Un riepilogo che include:

o   Numero di raccolte siti esaminate.

o   Se l'aggiornamento non viene eseguito, un elenco riepilogativo dei siti che dovranno essere aggiornati insieme a informazioni dettagliate sulla versione corrente di ogni caratteristica (ID) presente nella soluzione.

o   Se l'aggiornamento viene eseguito, informazioni sulle caratteristiche e le versioni con i dettagli sull'esito dell'aggiornamento, sull'esito della nuova installazione o sull'eventualità che la caratteristica non sia stata modificata perché già aggiornata.

Alcune osservazioni:

Per eseguire l'aggiornamento di una soluzione, nella piattaforma SharePoint 2010 i nomi dei file delle soluzioni devono essere diversi.  Se i nomi sono uguali, verrà visualizzato un errore in cui viene indicato che la soluzione è già attiva.  Quando si esegue l'aggiornamento di una soluzione, viene utilizzato l'ID soluzione per individuare le versioni esistenti della soluzione e QUINDI esaminare i dati relativi alle versioni.  L'aggiornamento comporterà solo il passaggio a una nuova versione.  Non consentirà di eseguire il rollback a una versione precedente.  Se le versioni sono uguali, non verrà eseguita alcuna azione.

Ci auguriamo che questo script si riveli utile per la gestione delle soluzioni che si intende distribuire e renda più semplici le operazioni di aggiornamento.

# 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()           

}

 

Data pubblicazione: 15/08/2010 23.30

Questo è un post di blog localizzato. L'articolo originale è disponibile in Managing Upgrades on Sandbox Solutions.