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.