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 = (Get-Content $fileName) Deploy-Solutions }catch{ Write-Host $_.Exception.Message -ForegroundColor Red throw "Exception occured 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 occured 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.
In this screen you will have to supply all required information:
Name: Deploy SharePoint Solutions
Description: Tool for deploying SharePoint solutions
Command: powershell (Because we would like to run powershell)
Arguments: -command .\Deploy-SPSolution.ps1 “__ConfigFileName__” “__Environment__”
Resources: functions.ps1 and Deploy-Solution.ps1
When specifying __ (double underscores) before and after a value in the arguments section Release Management will recognize this as a parameter that you can specify in for example the Release Template.
The executing part of the tool specifies what the Release Management agent should execute. In this example it will execute the PowerShell file “Deploy Solution.ps1” with the specified parameters. Because Release Management does not have this file included we add it as resource the same for the functions file.
A tool only cannot be used within a Release Template. In order to use it within a Release Template we also need to define a component. An component is a object that will take the files (from for example the build drop location) and combines it with the tool we specify (A component can do much more but is not relevant for this post).
To define a component go to: Configure Apps – Components and then select “New”. First step is to fill in a name and make a selection for the source. As we will use the drop location for the source select the option: Builds with application and enter “ \” as the path to the package. Configuring it this way will make sure that the root drop location is copied to the executing path of the build agent together with the tool files we will specify in the next step.
The tool needs to be specified in the deployment tab. The deployment tab is the action you would like to take (tool you would like to execute). Here we will select the tool we created and the other fields are filled in for us.
With all this in place we can save the component and use it within a Release Template. In Part 3 we will discuss how to create the release template together with the component and start the release template after a build.
Hi,
Can i have the entire source code for the config files and the powershell scripts?
Thanks..
Hi Kumar,
thanks for this wonderful article around deploying powershell via release management. one question though, is the functions.ps1 the script for the deploy-solutions?
Farah
Hi,
My name is Maik by the way. The functions.ps1 is a PowerShell file where in there are multiple functions, one of them is a function to deploy the solutions.