Gerenciando atualizações em soluções de área restrita
Gerenciando atualizações em soluções de área restrita
Texto:
As soluções de área restrita são um ótimo recurso na plataforma SharePoint 2010. Entretanto, à medida que essas soluções são implantadas em vários locais no farm ou no conjunto de sites, surge a questão: como gerenciá-las?
Nós fornecemos um script PowerShell para ajudá-lo com isso. É muito simples, mas é possível estender para fazer mais, de modo a se adaptar às ferramentas que você já está usando para gerenciar os farms e os conjuntos de sites.
Deixe-me descrever o que esse script faz:
Cada Solução de Área Restrita implantada tem uma ID de Solução associada. Dentro dessa Solução, você encontrará um ou mais recursos com uma ID de Recurso e um número de versão. Para uma determinada ID de solução, esse script percorrerá todo o farm ou conjunto de sites e gerará um log informando todos os locais em que a solução foi encontrada. Em seguida, examinará cada recurso na Solução e adicionará uma entrada ao log indicando qual versão desse recurso foi implantada. Também poderá executar a atualização se uma nova versão da Solução for fornecida. Esse é um sinalizador de que o script pode executar a atualização ou simplesmente ser usado como um meio de coletar informações sobre a solução.
Em seguida, o script utiliza os seguintes parâmetros:
· Caminho de Arquivo e Nome da Solução (arquivo .wsp) a ser atualizado
· Parâmetro de Opção que indica se a atualização deve ser executada ou não
Permissões:
· O script pressupõe que a pessoa que o executa é administrador e tem permissão para executar as ações de atualização.
· Os níveis de permissão são modificados para conceder Controle Total ao administrador.
· Após a conclusão da atualização, as configurações de permissões originais são restauradas.
O formato de log é o seguinte:
· Detalhes sobre o caminho de arquivo e o nome da solução que você está examinando, incluindo a ID da solução.
· Detalhes sobre cada conjunto de sites examinado
· Para cada conjunto de sites
o Informações sobre se uma solução correspondente foi encontrada ou não
o Caso tenha sido encontrada, detalhes sobre o arquivo de solução que está sendo removido para que seja possível substituí-lo pela nova versão.
o Se a atualização estiver sendo executada, detalhes sobre o sucesso ou a falha
· Um resumo que inclui
o Número de conjuntos de sites examinados
o Se a atualização não estiver sendo executada, uma lista resumida dos sites que exigirão atualização junto com os detalhes da versão atual para cada recurso (ID) na solução.
o Se a atualização FOI executada, as informações de recurso e versão são acompanhadas por detalhes sobre atualização bem-sucedida, nova instalação bem-sucedida ou o recurso permanece inalterado, pois já está atualizado.
Algumas observações:
Para atualizar uma solução, a plataforma SharePoint 2010 espera que os nomes de arquivos da solução sejam diferentes. Se forem iguais, você receberá um erro informando que a solução já está ativa. Quando você atualiza uma solução, a ID da solução é usada para localizar as versões existentes dessa solução e DEPOIS os detalhes da versão. A atualização apenas o levará para uma nova versão. Ela não reverterá para uma versão antiga. E se as versões forem iguais, nada será feito.
Esperamos que esse script ajude você a gerenciar as soluções que está implantando e a executar atualizações muito mais facilmente.
# 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()
}
Publicado em: 15/08/2010 23:30:00
Esta é uma postagem de blog traduzida. O artigo original pode ser encontrado em Gerenciando atualizações em soluções de área restrita