SharePoint: To Update or not to Update?
Based on Update-SPSolution reference,
The Update-SPSolution cmdlet upgrades a deployed SharePoint solution in the farm. Use this cmdlet only if a new solution contains the same set of files and features as the deployed solution. If files and features are different, the solution must be retracted and redeployed by using the Uninstall-SPSolution and Install-SPSolution cmdlets, respectively.
Given that Update-SPSolution is way more efficient than the alternative, it pays to see whether it can be leveraged.
So here is a PowerShell script that takes the full path of a .wsp file and a SPSolution, if it exists already in SharePoint, and compares one against the other to determine whether it is possible to get away by updating only instead of uninstalling, removing, adding and installing.
As you can see, it makes use of expand.exe to open the .wsp (cab) file. Therefore it assumes a specific format of its output. (Could be clearly made more robust by replacing expand.exe’s call with unpacking routine.)
function Get-WSPFileNames([string]$fullPathWSP)
{
[string[]]$e = & expand.exe -D $fullPathWSP
$f = [System.Array]::CreateInstance([object], $e.Length - 5)
[System.Array]::Copy($e, 3, $f, 0, $e.Length - 5)
$f
}
function Compare-WSPFileNames([string[]]$f1, [string[]]$f2)
{
if($f1.Length -ne $f2.Length)
{
throw "Arrays expected to have the same length."
}
for($i = 0; $i -lt $f1.Length; $i++)
{
$eq = $f1[0].Split(' ')[$f1[0].Split(' ').Length -1] -eq $f2[0].Split(' ')[$f2[0].Split(' ').Length -1]
if(!$eq)
{
return $false
}
}
return $true
}
function CompareWSPFiles([string]$fullPathWSP1, [string]$fullPathWSP2)
{
# read WSP's
$f1 = Get-WSPFileNames $fullPathWSP1
$f2 = Get-WSPFileNames $fullPathWSP2
# number of files
if($f1.Length -ne $f2.Length)
{
return $false
}
# files
if(-not (Compare-WSPFileNames $f1 $f2))
{
return $false
}
# seems they are same
return $true
}
function CompareWSP($fullPathWSP, $solution)
{
if($solution -eq $null -or !$solution.Deployed)
{
return $false
}
$tmp = [System.IO.Path]::GetTempFileName()
$solution.SolutionFile.SaveAs($tmp)
$same = CompareWSPFiles $fullPathWSP $tmp
return $same
}
function CanUpdateSolution($fullPathWSP, $solution)
{
return CompareWSP $fullPathWSP $solution
}