SharePoint 2013 Solution Deployment Script

A deployment script that would loop through the containing folder for any WSP solution files and deploy it to a predetermined Web Application was our original deployment method. Moving to a SharePoint 2013 deployment scheme, we had a few issues reusing our SharePoint 2010 solution deployment script. The primary problem that we came across was that our solutions were not being identified by the servers with their solution name (aka. their WSP file name). Every once in a while we would have duplicates or our solution would not deploy right out.

Sooooo, we created a new deployment method that was a more precise deployment method using the feature ID instead.

With this method each WSP file has to have an accompanying PowerShell deployment script. This ensured that the solution would be identified properly and we could reuse the same deployment script on any server (using a Web URL prompt).

Let me take you on a tour of what we have.

 

The Setup

The only two things that are hard coded are the Solution Name and the Feature ID. You can get the Feature ID from the solution properties in Visual Studio.

Expand your Features folder > Double Click on your feature name. The Feature ID field in the property window is what you want.

#Example parameters
$solutionName = 'MySolution.wsp'
$featureSiteId = '44452204-308b-4c22-bg10-19c45dadcc9d'

We added a loop that checks to make sure that the solution was installed and completed by polling the solution deployment timer job.

function WaitForJobToFinish()
{ 
 $JobName = "*solution-deployment*$solutionName*"
 $job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
 
 if ($job -eq $null) 
 {
 Write-Host 'Timer job not found'
 }
 else
 {
 $JobFullName = $job.Name
 Write-Host -NoNewLine "Waiting job" $JobFullName
 while ((Get-SPTimerJob $JobFullName) -ne $null) 
 {
 Write-Host -NoNewLine .
 Start-Sleep -Seconds 2
 }
 Write-Host "Finished!"
 }
}

We then needed to know what Web Application this solution was going to be installed on.

Param($parmWebUrl) #add this line to the very top of your PowerShell to check for a parameter.

if($parmWebUrl -eq $null) {
 $webUrl = read-host "Web URL? Enter for exit" 
}
else {
 $webUrl = $parmWebUrl 
}

if($webUrl -eq ""){break}

$web = Get-SPWeb $webUrl
$siteUrl = $web.Site.Url
$webApp = Get-SPWebApplication -Identity $siteUrl

 

Enable SP Admin Service

Ensure that the administration service is running on the server. This is a precaution in case it has been disabled.

#Enable Admin service
Write-Host "Checking SPAdmin Service"
$srvName = "SPAdminV4"
$service = Get-Service $srvName
$serviceStatus = $service.status
If ($serviceStatus -eq "Stopped") 
{
 Write-Host 'Starting SPAdmin Service'
 Start-Service $srvName
}
else
{
 Write-Host 'SPAdmin Service already started'
}

 

Disable/Uninstall > Install > Enable Solution

We do a complete deployment cycle by removing any existing solution then re-installing with an enable. We first used the Upgrade path but found that our files were not being truly updated.

#Disabling feature
Write-Host "Disabling feature"
Disable-SPFeature -Identity $featureSiteId -Url $siteUrl -Confirm:$false -force

$solution = Get-SPSolution | where {$_.Name -eq $solutionName } -ErrorAction SilentlyContinue
if($solution)
{
 if($solution.Deployed -eq $true)
 {
 Write-Host 'Unistalling solution'
 
 Uninstall-SPSolution -Identity $solutionName -WebApplication $siteUrl -confirm:$false 
 WaitForJobToFinish 
 }
 Write-Host 'Removing solution'
 Remove-SPSolution –Identity $solutionName -confirm:$false
}
#Add & Install Solution
Write-Host 'Adding solution'
$scriptPath = Split-Path -parent $MyInvocation.MyCommand.Definition

$solutionPath = "$scriptPath$solutionName"
$solution = Add-SPSolution $solutionPath

Write-Host 'Installing solution'
Install-SPSolution –Identity $solutionName –GACDeployment -WebApplication $siteUrl -Force
WaitForJobToFinish
#Restart-Service W3SVC -force
#Enable Features
Write-Host "Enabling feature"
Enable-SPFeature -Identity $featureSiteId -Url $siteUrl -Confirm:$false -force

if ($serviceStatus -eq "Stopped") 
{
 Write-Host 'Stopping SPAdmin Service'
 Stop-Service $srvName
}
Write-Host 'Deploy finished'

Our new deployment plan ensures that the correct solution is handled with each deploy. We also included additional checks along the way to ensure that our deployment wasn’t stepping on itself. We also added in a few user dialog responses to know where the script might have failed or what step it is on.

Give this a try and drop me a line if you see any room for improvement.

 

Full Code

Param($parmWebUrl)

$solutionName = ''
$featureSiteId = ''

function WaitForJobToFinish()
{
$JobName = "*solution-deployment*$solutionName*"
$job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
if ($job -eq $null)
  {
    Write-Host 'Timer job not found'
  }
else
  {
     $JobFullName = $job.Name
     Write-Host -NoNewLine "Waiting job" $JobFullName
     while ((Get-SPTimerJob $JobFullName) -ne $null)
       {
          Write-Host -NoNewLine .
          Start-Sleep -Seconds 2
       }
     Write-Host "Finished!"
  }
}

if($parmWebUrl -eq $null) {
     $webUrl = read-host "Web URL? Enter for exit"
}
else {
     $webUrl = $parmWebUrl
}

if($webUrl -eq ""){break}

$web = Get-SPWeb $webUrl
$siteUrl = $web.Site.Url
$webApp = Get-SPWebApplication -Identity $siteUrl

#Enable Admin service
Write-Host "Checking SPAdmin Service"
$srvName = "SPAdminV4"
$service = Get-Service $srvName
$serviceStatus = $service.status
If ($serviceStatus -eq "Stopped") 
{
     Write-Host 'Starting SPAdmin Service'
     Start-Service $srvName
}
else
{
     Write-Host 'SPAdmin Service already started'
}

#Disabling feature
Write-Host "Disabling feature"
Disable-SPFeature -Identity $featureSiteId -Url $siteUrl -Confirm:$false -force

$solution = Get-SPSolution | where {$_.Name -eq $solutionName } -ErrorAction SilentlyContinue
if($solution)
{
 if($solution.Deployed -eq $true)
 {
    Write-Host 'Unistalling solution'
 
    Uninstall-SPSolution -Identity $solutionName -WebApplication $siteUrl -confirm:$false 
    WaitForJobToFinish 
 }
 Write-Host 'Removing solution'
 Remove-SPSolution –Identity $solutionName -confirm:$false
}

#Add & Install Solution
Write-Host 'Adding solution'
$scriptPath = Split-Path -parent $MyInvocation.MyCommand.Definition

$solutionPath = "$scriptPath$solutionName"
$solution = Add-SPSolution $solutionPath

Write-Host 'Installing solution'
Install-SPSolution –Identity $solutionName –GACDeployment -WebApplication $siteUrl -Force

WaitForJobToFinish

#Restart-Service W3SVC -force
#Enable Features
Write-Host "Enabling feature"
Enable-SPFeature -Identity $featureSiteId -Url $siteUrl -Confirm:$false -force
if ($serviceStatus -eq "Stopped") 
{
    Write-Host 'Stopping SPAdmin Service'
    Stop-Service $srvName
}

Write-Host 'Deploy finished'

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.