In previous post(s) I described deploying your solutions with PowerShell. Lately I encountered the situation I had to deploy a solution language pack. This is a regular WSP file with the same Solution ID as the original solution, but containing localization resources for specific languages. The purpose of solution language packs is to add localization for additional languages after the original solution package has already been distributed without having to upgrade the original solution package. I suggest you read this MSDN article about Working with Language Pack Farm Solutions.
Deployment
For deploying these solution language packs the same PowerShell cmdlets can be used: Add-SPSolution and Install-SPSolution. However, this time the –Language parameter must be used. Keep in mind that the original solution is deployed first.
Removal
For removing these solution language packs the same PowerShell cmdlets can be used: Remove-SPSolution and Uninstall-SPSolution. Again, the –Language parameter must be used. Also, the original solution is still present in the farm.
Extending the script
So, how can we fit this deployment and removal in our existing script Solutions.ps1?
First of all, we need to tell our script we’re dealing with a solution language pack. I have created a Solution.xml file with solutions to deploy, remove or update (I kept it simple):
<Solutions> <Solution file="..SharePointLearningKit.wsp" deploy="TRUE" remove="TRUE" update="FALSE" /> <Solution file="..SharePointLearningKit-1043.wsp" deploy="TRUE" remove="TRUE" update="FALSE" lcid="1043" /> </Solutions>
The lcid attribute tells the script that it is a solution language pack and which language it is. Another important thing is that I have named the wsp file correctly: the same name as the original code solution and a suffix “-{lcid}”. I will use this in the scripts.
Secondly, our deploy.ps1 (and also remove.ps1 and update.ps1) needs to be changed in order to use the Solutions.xml file.
$deployConfig = Get-Content Solutions.xml foreach( $solution in $deployConfig.Solutions.Solution ) { if( $solution.deploy.ToUpper().Equals("TRUE") ) { if( $solution.lcid ) { .solution.ps1 -solution $solution.file -deploy -url $url -language $solution.lcid } else { .solution.ps1 -solution $solution.file -deploy -url $url } } }
When the solution configuration item contains a lcid attribute it calls the solution.ps1 script with the language parameter provided with the lcid value.
Third and final step is to change the solution.ps1 script to actually deploy (or remove or update) the solution language pack. As just mentioned the solution.ps1 script has an additional parameter Language:
param( [string]$solution, [string]$url, [switch]$deploy = $false, [switch]$remove = $false, [switch]$update = $false, [int]$language )
Then if $language is provided (the actual value will be greater then 0), we are dealing with a solution language pack and we need to know the name of the original solution.
# locate the solution file: $solutionFile = Get-ChildItem $solution # get the solution Name $solutionName = [System.IO.Path]::GetFilename($solutionFile) if( $language) { #solutionCoreName is the name of the original solution package $solutionCoreName = $solutionName.Replace( "-$language", "" ) }
For deployment, the script looks like this:
if($deploy){ Write-Host "" Write-Host -ForegroundColor Yellow "Installing " -NoNewline Write-Host -ForegroundColor Green $solutionName -NoNewline if( $language ) { Write-Host -ForegroundColor Green "($language)" } else { Write-Host "" } if( $language ) { $sol = Get-SPSolution $solutionCoreName -ErrorAction SilentlyContinue $sol = $sol.LanguagePacks | where-object { $_.LocaleId -eq $language } } else { $sol = Get-SPSolution $solutionName -ErrorAction SilentlyContinue } if ($sol) { Write-Host -ForegroundColor yellow "$solutionName already installed in this farm" } else { Write-Host -ForegroundColor yellow "Adding to the farm" -NoNewline if( $language ) { Write-Host -ForegroundColor yellow " with langauge $language" -NoNewline $sol = Add-SPSolution $solutionFile -Language $language } else { $sol = Add-SPSolution $solutionFile } Write-Host -ForegroundColor Green " DONE" } if( $language ) { $sol = $sol.LanguagePacks | where-object { $_.LocaleId -eq $language } if ( $sol.ContainsWebApplicationResource ) { Write-Host -ForegroundColor yellow "Deploying to $url" -NoNewline Install-SPSolution -Identity $solutionCoreName -GacDeployment -CasPolicies -Language $language -Webapplication $url } else { Write-Host -ForegroundColor yellow "Deploying" -NoNewline Install-SPSolution -Identity $solutionCoreName -GacDeployment -CasPolicies -Language $language } } else { if ( $sol.ContainsWebApplicationResource ) { Write-Host -ForegroundColor yellow "Deploying to $url" -NoNewline Install-SPSolution -Identity $solutionName -GacDeployment -CasPolicies -Webapplication $url } else { Write-Host -ForegroundColor yellow "Deploying" -NoNewline Install-SPSolution -Identity $solutionName -GacDeployment -CasPolicies } } if( $language) { $sol = Get-SPSolution $solutionCoreName $sol = $sol.LanguagePacks | where-object { $_.LocaleId -eq $language } } else { $sol = Get-SPSolution $solutionName } if ($sol.Deployed -eq $false ) { $counter = 1 while( ($sol.JobExists -eq $true ) -and ( $counter -lt $safeguard ) ) { Write-Host -ForegroundColor yellow "." -NoNewline sleep $sleeptime $counter++ } } Write-Host -ForegroundColor Green " DONE" }
The interesting part is to get a reference to the solution language pack. First, get the original solution. It has a LanguagePacks property that returns the list of language packages associated with this solution. I want to have a reference to my language pack:
$sol = Get-SPSolution $solutionCoreName -ErrorAction SilentlyContinue $sol = $sol.LanguagePacks | where-object { $_.LocaleId -eq $language }
If $sol is not null, I know the solution language pack is present in the farm. If it is null then I can add it and deploy it.
Similar lines of code are for the remove and update scenario’s. I have all script files zipped and it can be downloaded here.