Create a custom component to deploy SharePoint Solutions – Part 2
In the first part of the series we have adjusted a build template in order to copy content from source control to the drop location after the build. This content can then be used to supply release management with information about the deployment. This functionality will be used to copy a configuration file to the drop location. With PowerShell were our custom component will exist off we can read out that configuration file.
As you can read we will create our custom component in specific steps and we will start with the configuration file.
Configuration File
The configuration file will contain all of the information that is needed to deploy a SharePoint solution package. As example you would like to know to which web application the solution needs to be deployed to.
As example take a look at the following sample configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<!--
Section to specify the configuration for the deployment
-->
<Configuration>
<!--
Section to specify environment information
-->
<Environment>
<DEV>
<WebApplications>
<WebApplication ID="1" Url="http://sample.msftplayground.local"></WebApplication>
</WebApplications>
</DEV>
<TST>
<WebApplications>
<WebApplication ID="1" Url="http://sample-tst.msftplayground.local"></WebApplication>
</WebApplications>
</TST>
<ACC>
<WebApplications>
<WebApplication ID="1" Url="http://sample-acc.msftplayground.local"></WebApplication>
</WebApplications>
</ACC>
<PROD>
<WebApplications>
<WebApplication ID="1" Url="http://sample.msftplayground.local"></WebApplication>
</WebApplications>
</PROD>
</Environment>
<!--
Section to specify information on solutions were to deploy to or retract.
-->
<Solutions>
<!--
Section to specify the solutions that need to deployed.
-->
<Deploy>
<!--
Section to specify specific solution information
Name = Name of the solution
Upgrade = Upgrade the solution if it exists
DeployToAll = Deploy to all content applications
DeployNotExits = Deploy the solution if it does not exist when upgrade is set to true
WebApplication = The web application to deploy to specified with the ID when deploy to all is false
-->
<Solution Name="MSFTPlayground.SharePoint.wsp" Upgrade="true" DeployToAll="false" DeployNotExists="true">
<WebApplication ID="1" />
<WebApplication ID="2" />
<WebApplication ID="3" />
</Solution>
</Deploy>
<Retract>
<!--
Section to specify specific solution information
Name = Name of the solution
Remove = Remove the solution after retraction
RetractAll = Retract from all content applications
-->
<Solution Name="MSFTPlayground.SharePoint.wsp" Remove="true" RetractAll="true">
<WebApplication ID="1" />
<WebApplication ID="2" />
<WebApplication ID="3" />
</Solution>
</Retract>
</Solutions>
</Configuration>
In the configuration file you can specify which solution package you would like to deploy and to what web application. The web applications are specified in the “Environment” section. The configuration file contains a “Environment” section to be able to use the same mechanism for multiple environments that use different URLs. Within the solution section we then refer to a specific web application by its ID.
To make it more complex we also added some other properties (Upgrade, DeployToAll) to make the components more advanced.
PowerShell
With the configuration file we can start writing the PowerShell that will read out the configuration file and deploys the solution.
param(
[string]$filename = $(throw "Specify the Config filename that is located in the drop folder"),
[string]$environment = $(throw "Specify the Environment you would like to deploy to.")
)
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) {
Write-Host "Loading Microsoft SharePoint PowerShell" -ForegroundColor Green
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
Write-Host "#### Start deploying solutions ####"
if ((Test-Path $fileName) -eq $true) {
. ".\functions.ps1"
Write-Host "Loading configuration file $filename" -ForegroundColor Green
try{
$config = [xml] (Get-Content $fileName)
Deploy-Solutions
}catch{
Write-Host $_.Exception.Message -ForegroundColor Red
throw "Exception occurred while deploying solutions"
}
}else {
throw "Error loading configuration file, exiting the deployment"
}
Write-Host "#### End deploying solutions ####"
This PowerShell file needs to be run with two parameters:
- Filename: The path to the configuration file in the drop location.
- Environment: The environment you would like to deploy to. This should be the same as the environment section you have specified in the configuration file.
Within the PowerShell file the SharePoint PowerShell module is loaded and besides that I load a custom functions file. In the functions file I have a couple of PowerShell methods that I use to do some advanced stuff on the configuration file, and also some more SharePoint functions. When everything is loaded the configuration file is loaded in the config variable and we call the function “Deploy-Solutions” that is within the same file.
function Deploy-Solutions(){
$path = ".\";
$type = "Deploy";
foreach($solution in $config.Configuration.Solutions.Deploy.Solution){
$solutionName = $solution.Name;
$currentDirectory = Get-Location
$solutionPath = [IO.Path]::GetFullPath([String]::Concat($currentDirectory, "\" ,$path, "\", $solutionName))
Write-Host " > Solution path is '$solutionPath'" -ForegroundColor Yellow
$webApplicationScoped = Get-SolutionProperty $solutionName "ContainsWebApplicationResource"
$solutionDeployed = Get-SolutionProperty $solutionName "Deployed"
[bool]$deployToAll = Check-SolutionConfigProperty $solutionName "DeployToAll" $type
[bool]$upgrade = Check-SolutionConfigProperty $solutionName "Upgrade" $type
[bool]$deployNotExists = Check-SolutionConfigProperty $solutionName "DeployNotExists" $type
$webApps = Get-WebAppsForSolution $solutionName $environment $type
# Check if file exists
if ((Test-Path $solutionPath) -eq $false) {
Write-Host " > Solution file doesn't exist!" -ForeGroundColor Red
throw "Solution file doesn't exist!";
}
$deploySolution = $false;
if (Check-SolutionExists $solutionName) {
Write-Host " > Solution exists in solution store" -ForegroundColor Yellow
if(!$upgrade){
Write-Host " > Solution exists in solution store" -ForegroundColor Yellow
if($solutionDeployed) {
Write-Host " > Solution is deployed, uninstall solution $solutionName" -ForegroundColor Yellow
if ($webApplicationScoped) {
$solution = Get-SPSolution $solutionName
$deployedTo = $solution.DeployedWebApplications
foreach ($webApp in $deployedTo) {
Write-Host " > Uninstall from web application '$webApp'" -ForeGroundColor Yellow
Uninstall-SPSolution -Identity $solutionName -WebApplication $webApp -Confirm:$false -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
}
} else {
Write-Host " > Solution doesn't contain web application resource, uninstall globally." -ForeGroundColor Yellow
Uninstall-SPSolution -Identity $solutionName -Confirm:$false -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
}
Write-Host " > Solution uninstalled" -ForeGroundColor Green
}
Write-Host " > Remove solution $solutionName from solution store" -ForeGroundColor Yellow
Remove-SPSolution -Identity $solutionName -Confirm:$false -ErrorAction Stop
Write-Host " > Solution removed" -ForeGroundColor Green
$deploySolution = $true
}else{
Write-Host " > Upgrade SPSolution $solutionName" -ForegroundColor Yellow
Update-SPSolution -LiteralPath $solutionPath -Identity $solutionName -Force -GACDeployment -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
$deploySolution = $false
}
}else{
Write-Host " > Solution does not exists in solution store" -ForegroundColor Yellow
if(($upgrade -And $deployNotExists)){
Write-Host " > Solution does not exists and will be added because it needed to be deployed when it did not exists" -ForegroundColor Yellow
$deploySolution = $true
}
if(!($upgrade)){
Write-Host " > Solution does not exists and will be added in order to deploy" -ForegroundColor Yellow
$deploySolution = $true
}
}
if($deploySolution){
Write-Host " > Add solution $solutionName to solution store" -ForeGroundColor Yellow
Add-SPSolution -LiteralPath $solutionPath -ErrorAction Stop
Write-Host " > Solution added" -ForeGroundColor Green
Write-Host " > Deploy solution $solutionName" -ForeGroundColor Yellow
$webApplicationScoped = Get-SolutionProperty $solutionName "ContainsWebApplicationResource"
if ($webApplicationScoped) {
if ($deployToAll) {
Write-Host " > Deploying to all Web Applications" -ForeGroundColor Yellow
Install-SPSolution –Identity $solutionName -GACDeployment -AllWebApplications -Force -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
} else {
foreach ($webApp in $webApps) {
Write-Host " > Deploying to $webApp" -ForeGroundColor Yellow
Install-SPSolution –Identity $solutionName -WebApplication $webApp -Force -GACDeployment -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
}
}
} else {
Install-SPSolution –Identity $solutionName -GACDeployment -Force -ErrorAction Stop
Wait-ForJobToFinish($solutionName)
}
}
$success = Get-SPSolutionSuccessState $solutionName
if($success){
Write-Host " > Solution $solutionName installed" -ForeGroundColor Green
}
else{
Write-Host " > Solution $solutionName could not be installed correctly." -ForeGroundColor Green
throw "Error occurred while installing solution $solutionName"
}
}
}
In the Deploy-Solution function we navigate trough the xml and deploy the solution packages specified in the configuration file. Within the Deploy-Solution function we also use some functions that are specified in the functions.ps1 file.
With the PowerShell files in place we can start adding things to Release Management. The first action in Release Management is creating a new Tool. By going to “Inventory” – “Tools” and click “New” to create a new tool.