Deploy solution wsp to SharePoint

The Microsoft technet article Automated Farm level Solution Deployment and Retraction, gives a very good example of deploying SharePoint wsp solutions using PowerShell. However, I felt that it would be better to wait for the timer job to complete instead of using sleep command as mentioned in SharePoint 2010: PowerShell to Wait for WSP Solution Deployment Timer Job to Complete

Also, I thought it would be better if we added a configuration xml instead of providing input parameters.

Please feel free to let me know if this script can be enhanced by leaving a comment

We can have a configuration file which contains information such as web application url, site collection and web specific information such as features to be activated. It can have any number of Site and Web sections to handle multiple site collections and webs.

Configuration Config.xml:

<WebApp>
  <WebAppUrl>http://server/webapp</WebAppUrl>
  <Site>
    <SiteUrl>http://server/sites/site1</SiteUrl>
    <Features>
       <Feature>PublishingSite</Feature>
    </Features>
  </Site>
  <Web>
    <WebUrl>http://server/sites/site1</WebUrl>
    <Features>
      <Feature>PublishingWeb</Feature>
    </Features>
  </Web>
</WebApp>

Ensure that the wsps are kept in a subfolder called WSP inside the folder where the script is saved.

So, here is the enhanced script

Powershell Script

[ps]
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq ‘Microsoft.SharePoint.Powershell’}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell"
}
#get the configuration info
$config = [xml](Get-Content "Config.xml");

$wspFolderPath = "WSP";
[int]$sleepTime = 4;
$AdminServiceName = "SPAdminV4";
$TimerServiceName = "SPTimerV4";
$url = $config.WebApp.WebAppUrl;

#Start the Admin service if it is not started
if ($(Get-Service $AdminServiceName).Status -eq "Stopped")
{
Start-Service $AdminServiceName
Write-Host "Started the SharePoint 2013 Admin Service"
}

#Start the Timer service if it is not started
if ($(Get-Service $TimerServiceName).Status -eq "Stopped")
{
Start-Service $TimerServiceName
Write-Host "Started the SharePoint Timer Job"
}

function DeactivateSiteFeatures($siteCol)
{
$siteUrl = $siteCol.SiteUrl
$Site = Get-SPSite -Identity $siteUrl
foreach ($featureName in $siteCol.Features.Feature)
{
$EnabledSiteFeatures = Get-SPFeature -site $siteUrl
foreach($enabledFeature in $EnabledSiteFeatures)
{
#Check if feature is already activated. Deactivate if already activated.
if($featureName -eq $enabledFeature.DisplayName)
{
Write-Host "Feature $featureName Activated" -foregroundcolor Green
Write-Host "- Deactivating Feature" -foregroundcolor Yellow
Start-Sleep 3
Disable-SPFeature -Identity $featureName -url $SiteUrl -confirm:$false
Write-Host " — Feature deactivated successfully" -foregroundcolor Green
}
}
}
$Site.Dispose()
}

function ActivateSiteFeatures($siteCol)
{
$siteUrl = $siteCol.SiteUrl
$Site = Get-SPSite -Identity $siteUrl
foreach ($featureName in $siteCol.Features.Feature)
{
Write-Host "Activating $featureName feature" -foregroundcolor Yellow
Enable-SPFeature -identity $featureName -Url $SiteUrl -Confirm:$false
Start-Sleep 3
Write-Host " — Feature activated successfully" -foregroundcolor Green
}
$Site.Dispose()
}

function DeactivateWebFeatures($PubWeb)
{
Write-Host "Deactivating Web features"
#Web
$WebUrl = $PubWeb.WebUrl

foreach ($featureName in $PubWeb.Features.Feature)
{
Write-Host " "

$EnabledWebFeatures = Get-SPFeature -Web $WebUrl

foreach($enabledFeature in $EnabledWebFeatures)
{
#Check if feature is activated. Deactivate if activated.
if($featureName -eq $enabledFeature.DisplayName)
{
Write-Host "Feature $featureName already Activated" -foregroundcolor Green
Write-Host "- Deactivating Feature" -foregroundcolor Yellow
Start-Sleep 3
Disable-SPFeature -Identity $featureName -url $WebUrl -confirm:$false
Write-Host " — Feature deactivated successfully" -foregroundcolor Green
}
}
}
}

function ActivateWebFeatures($PubWeb)
{
Write-Host "Activating Web features"
#Web
$WebUrl = $PubWeb.WebUrl

foreach ($featureName in $PubWeb.Features.Feature)
{
Write-Host "Activating $featureName feature" -foregroundcolor Yellow
Enable-SPFeature -identity $featureName -Url $WebUrl -Confirm:$false
Start-Sleep 3
Write-Host " — Feature activated successfully" -foregroundcolor Green
}

}
function WaitForSPSolutionJobToComplete($solution)
{
if ($solution)
{
$solutionName = $solution.Name;
if ($solution.JobExists)
{
Write-Host -NoNewLine "Waiting for timer job to complete for solution ‘$solutionName’."
}

# Check if there is a timer job still associated with this solution and wait until it has finished
while ($solution.JobExists)
{
$jobStatus = $solution.JobStatus

# If the timer job succeeded then proceed
if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Succeeded)
{
Write-Host "Solution ‘$solutionName’ timer job suceeded"
return $true
}

# If the timer job failed or was aborted then fail
if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Aborted -or
$jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Failed)
{
Write-Host "Solution ‘$solutionName’ has timer job status ‘$jobStatus’."
return $false
}

# Otherwise wait for the timer job to finish
Write-Host -NoNewLine "."
Sleep 1
}

# Write a new line to the end of the ‘…..’
Write-Host
}

return $true
}

#deactivate site collection features
foreach ($siteCollection in $config.WebApp.Site)
{
DeactivateSiteFeatures($siteCollection)
}

#deactivate web features
foreach ($web in $config.WebApp.Web)
{
DeactivateWebFeatures($web)
}

#WSP Solution
foreach($filename in Get-ChildItem $wspFolderPath)
{
Write-Host " "
$SolutionPackageName = $filename.name
$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionPackageName) -and ($_.Deployed -eq $true)}
if ($Solution -ne $null)
{
Write-Host "Solution already Deployed. Rectracting solution: $SolutionPackageName" -foregroundcolor Red
if($Solution.ContainsWebApplicationResource)
{
Uninstall-SPSolution $SolutionPackageName -WebApplication $url -Confirm:$false
}
else
{
Uninstall-SPSolution $SolutionPackageName -Confirm:$false
}

# Calling Function to wait for timer job to compelete
WaitForSPSolutionJobToComplete($Solution)

Write-Host "-Rectracting $SolutionPackageName solution Done." -foregroundcolor Green

if ($(Get-SPSolution | ? {$_.Name -eq $SolutionPackageName}).Deployed -eq $false)
{
Write-Host "Removing solution: $SolutionPackageName" -foregroundcolor Red
Remove-SPSolution $SolutionPackageName -Confirm:$false
Start-Sleep -Seconds $sleepTime
Write-Host " – Removing $SolutionPackageName solution Done." -foregroundcolor Green
}
}

Write-Host "-Adding solution: $SolutionPackageName" -foregroundcolor Green
$SolutionPath = $PSScriptRoot + "\" +$wspFolderPath +"\"+ $SolutionPackageName
Add-SPSolution $SolutionPath | Out-Null
Start-Sleep -Seconds $sleepTime
Write-Host " – Adding $SolutionPackageName Solution Done." -foregroundcolor Green

Write-Host "-Deploying solution: $SolutionPackageName" -foregroundcolor Green
$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionPackageName) -and ($_.Deployed -eq $false)}
if(($Solution -ne $null) -and ($Solution.ContainsWebApplicationResource))
{
Install-SPSolution $SolutionPackageName -WebApplication $url -GACDeployment -Confirm:$false
}
else
{
Install-SPSolution $SolutionPackageName -GACDeployment -Confirm:$false
}

# Calling Function to wait for timer job to compelete
WaitForSPSolutionJobToComplete($Solution)

Write-Host
Write-Host " – Deploying $SolutionPackageName solution Done." -foregroundcolor Green
}

#loop all the site collections
foreach ($siteCollection in $config.WebApp.Site)
{
ActivateSiteFeatures($siteCollection)
}

#loop all the webs
foreach ($web in $config.WebApp.Web)
{
ActivateWebFeatures($web)
}
[/ps]

Please let me know your thoughts.

Leave a Reply

Your email address will not be published. Required fields are marked *