管理沙盒解决方案的升级
管理沙盒解决方案的升级
正文:
沙盒解决方案是 SharePoint 平台上的一项重要功能。 但是由于这些解决方案部署在您的服务器场或网站集中的各个不同位置,因此如何管理这些解决方案的问题也就随之产生了。
我们将提供一个 PowerShell 脚本来帮助您实现此目标。 该脚本非常简单,但可以进行扩展来完成更多功能,从而适合您已经用于管理服务器场和网站集的工具。
首先让我来介绍该脚本的作用:
部署的每个沙盒解决方案都有关联的解决方案 ID。 在该解决方案内,您会发现一个或多个具有功能 ID 和版本号的功能。 对于给定的解决方案 ID,该脚本将检查整个服务器场或网站集并生成一个日志,告诉您发现该解决方案的所有位置。 然后,它会查看解决方案内的各个功能, 并添加一个日志条目,以指示所部署功能的版本。 如果提供解决方案的新版本,它还会执行升级。 这是一个标记,以指示该脚本是可以执行升级还是只用作收集解决方案信息的一种方式。
该脚本使用以下参数:
· 要升级的解决方案(.wsp 文件)的文件路径和名称
· 指示是否应执行升级的开关参数
权限:
· 该脚本假设运行它的人员是服务器管理员并且能够执行升级操作。
· 将修改权限级别以便向管理员授予完全控制权限。
· 升级完成后,权限将恢复为原来的设置。
日志格式如下所示:
· 您要检查的解决方案的文件路径和名称的详细信息,包括解决方案 ID。
· 所检查的每个网站集的详细信息
· 对于每个网站集
o 有关是否找到匹配的解决方案的信息
o 如果找到匹配的解决方案,则显示将被删除以便由新版本取代的解决方案文件的详细信息。
o 如果执行升级,则显示有关成功或失败的详细信息
· 摘要包括
o 所检查的网站集的数目
o 如果不执行升级,则显示需要升级的网站的摘要列表,以及解决方案中每个功能 (ID) 的当前版本的详细信息。
o 如果执行升级,则显示功能和版本信息以及有关成功升级、成功安装新版本或由于已经是最新而未发生更改的功能的详细信息。
几个注意事项:
若要升级解决方案,SharePoint 2010 平台需要不同的解决方案文件名。 如果解决方案文件名相同,将会出现错误,告诉您解决方案已经处于活动状态。 在升级解决方案时,将使用解决方案 ID 来查找该解决方案的现有版本,然后查看版本详细信息。 升级过程只能将您移到新版本, 而不会回滚到旧版本。 如果版本相同,则它不会执行任何操作。
我们希望此脚本能够帮助您更轻松地管理所部署的解决方案并执行升级。
# 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()
}
发布时间: 2010 年 8 月 15 日 晚上 11:30
这是一篇本地化的博客文章。请访问 Managing Upgrades on Sandbox Solutions 以查看原文