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'