sharepoint-deployment-scripting-with-powershell
PowerShell scripting approach for SharePoint (via psake)
This is a simple plea to SharePointers. Can we please have a decent build runner around PowerShell scripts in the deployment environment. Most developers in other frameworks do. So I thought that I would outline some basic techniques. psake is as good as any other options (except rake which I still think is vastly superior but I don’t want the operational hassle of needing it in other environments). Here’s what I’m doing:
- powershell wrapped in psake
- modularised scripts
- psake helpers scripts for the real world (and documented in other places)
- helper scripts for each of access to command line powershell
One caveat, psake has a couple of limitations that make it otherwise a good rake port:
- it doesn’t namespace (AFAIK) tasks and that means it effectively works in the global namespace – this means we get conflicts and have to resort to poor naming practices
- it doesn’t create good documentation for nested scripts – that seriously sucks – I want to be able to do
-docsand read what I can do - it really doesn’t do logging well when moving across scripts
(Start-Transcriptseems to suck – but that might be my knowledge)
If you don’t go down this road what you end up with is a load of powershell scripts that we double click on. That’s not my idea of well structured or maintainable. Skip straight down to deploy.ps1 if want to see what the scripts look like rather than all the plumbing. And, yes, there is way too much plumbing! Here is the script where I actually do the packaging up of these files.
File layout
default.ps1
here.cmd
deploy.cmd
scripts/
psake.psm1
psake1.ps1
deploy.ps1
install.ps1
wsp/
MySolution.wsp
Quick explanation:
psake1.ps1, psake.psm1– both come with psake. psm is a module and the make DSL engine – go there to understand what to do. psake1 is a help wrapper.default.ps1is a manifest that links all your psake tasks – psake looks for default.ps1 by, well, default.deploy.cmdis a GUI-based wrapper that invoke a specific tasks (deploy in this case)here.cmdbrings up a command line interface so that I can use all the psake tasks (egInvoke-psake Deploy)deploy.ps1, install.ps1are my two specific sets of tasks – deploy has SharePoint cmdlets linked in here (install is a further wrapper that does logging and in my own case also invokes other scripts I haven’t included like migrations)
How to use
Option One:
- Click
deploy.cmd
Option Two:
- Click
here.cmd– this will list out the available commands - Be able to type in powershell commands
Invoke-psake Deploy
Files
deploy.cmd
powershell -ExecutionPolicy Unrestricted -NoExit -Command "&{import-module .\scripts\psake.psm1; Invoke-Psake Install}"
default.ps1
Include .\scripts\deploy.ps1; Include .\scripts\install.ps1
here.cmd
powershell -ExecutionPolicy Unrestricted -NoExit -Command " &{import-module .\scripts\psake.psm1; Invoke-Psake -docs}"
psake.ps1
import-module .\scripts\psake.psm1 Start-Transcript -Path .\install.log invoke-psake @args Stop-Transcript remove-module psake
deploy.ps1
$framework = '3.5x64'
Properties {
$base_dir = resolve-path .
$solution = "MySolution.wsp"
$application = $null
$path = "$base_dir\wsp\$solution"
$SolutionFileName = ""
}
Task Deploy -Depends Solution-Setup, Solution-UnInstall, Solution-Remove, Solution-Add, Solution-Install, Solution-TearDown
Task Solution-Remove -Depends Solution-Wait{
Write-Host 'Remove solution'
Remove-SPSolution ñidentity $solution -confirm:$false
}
Task Solution-Add {
Write-Host 'Add solution'
Add-SPSolution -LiteralPath $path
}
Task Solution-Install {
Write-Host 'install solution'
if($application -eq $null)
{
Install-SPSolution -identity $solution -GACDeployment -force
}
else
{
Install-SPSolution -identity $solution -application $application -GACDeployment -force
}
}
Task Solution-UnInstall {
Write-Host 'uninstall solution'
if($application -eq $null)
{
Uninstall-SPSolution -identity $solution -confirm:$false
}
else
{
Uninstall-SPSolution -identity $solution -application $application -confirm:$false
}
}
Task Solution-Setup {
Add-PsSnapin Microsoft.SharePoint.PowerShell
}
Task Solution-TearDown -Depends Solution-Wait {
Remove-PsSnapin Microsoft.SharePoint.PowerShell
}
Task Solution-Wait {
$JobName = "*solution-deployment*$SolutionFileName*"
$job = Get-SPTimerJob | ?{ $_.Name -like $JobName }
if ($job -eq $null)
{
Write-Host 'Timer job not found'
}
else
{
$JobFullName = $job.Name
Write-Host -NoNewLine "Waiting to finish job $JobFullName"
while ((Get-SPTimerJob $JobFullName) -ne $null)
{
Write-Host -NoNewLine .
Start-Sleep -Seconds 2
}
Write-Host "Finished waiting for job.."
}
}
install.ps1
Task Install -Depends Logging-Start, Deploy, Logging-Stop
Task Logging-Start {
Start-Transcript -Path .\install.log
}
Task Logging-Stop {
Stop-Transcript
}