While cleaning up some PowerShell installations scripts that I wrote some time ago, I come across the following piece of code (modified slightly for anonymity) for creating a hierarchy of SharePoint sites and setting the locale for a subset of the sites. It works but it sure doesn’t adhere to the DRY principle.
New-SPWeb -url $base_url -addtoquicklaunch -template "STS#1" -name "Base" New-SPWeb -url $base_url/Dk -addtoquicklaunch -template "STS#1" -name "Dk" New-SPWeb -url $base_url/Uk -addtoquicklaunch -template "STS#1" -name "Uk" New-SPWeb -url $base_url/Dk/BusinessUnit1 -addtoquicklaunch -template "STS#1" -name "BusinessUnit1" New-SPWeb -url $base_url/Dk/BusinessUnit2 -addtoquicklaunch -template "STS#1" -name "BusinessUnit2" New-SPWeb -url $base_url/Uk/BusinessUnit1 -addtoquicklaunch -template "STS#1" -name "BusinessUnit1" New-SPWeb -url $base_url/Uk/BusinessUnit2 -addtoquicklaunch -template "STS#1" -name "BusinessUnit2" $dk = Get-SPWeb $base_url/Dk $dkBusinessUnit1 = Get-SPWeb $base_url/Dk/BusinessUnit1 $dkBusinessUnit2 = Get-SPWeb $base_url/Dk/BusinessUnit2 $locale = [System.Globalization.CultureInfo]::CreateSpecificCulture("da-DK") $dk.Locale = $locale $dk.Update() $dkBusinessUnit1.Locale = $locale $dkBusinessUnit1.Update() $dkBusinessUnit2.Locale = $locale $dkBusinessUnit2.Update()
How can we reduce this repetition? Well, it repeats because we’ve made the common mistake of mixing logic with data. One way to separate the two is using a table-driven approach, i.e., extract the varying parts, the data, into a table and rewrite the logic so it’s parameterized by the table. After some experimentation with PowerShell here’s the code I ended up with:
$sites = @( @("", "Base"), @("Dk", "Dk", "da-DK"), @("Uk", "Uk"), @("Dk/BusinessUnit1", "BusinessUnit1", "da-DK"), @("Dk/BusinessUnit2", "BusinessUnit2", "da-DK"), @("Uk/BusinessUnit1", "BusinessUnit1"), @("Uk/BusinessUnit2", "BusinessUnit2") ) $sites | foreach { $url, $title, $culture = $_ $newSite = New-SPWeb -url "$base_url/$url" -addtoquicklaunch -template "STS#1" -name $title if ($culture -ne "") { $locale = [System.Globalization.CultureInfo]::CreateSpecificCulture($culture) $newSite.Locale = $locale $newSite.Update() } }
So far so good. The un-installation part of the script, however, follows the same pattern of repetition:
Remove-SPWeb -identity $base_url/Uk/BusinessUnit2 -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url/Uk/BusinessUnit1 -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url/Dk/BusinessUnit2 -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url/Dk/BusinessUnit1 -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url/Dk -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url/Uk -confirm:$false -ErrorAction SilentlyContinue Remove-SPWeb -identity $base_url -confirm:$false
But now that we have the table of sites at hand, we can easily make the site removal table-driven as well:
function Reverse($array) { $clone = $array.Clone() [Array]::Reverse($clone) $clone } Reverse($sites) | foreach { $url = $_[0] Remove-SPWeb -identity "$base_url/$url" -confirm:$false -ErrorAction SilentlyContinue }
I’m sure the code could be written more elegantly, but given my working knowledge of PowerShell I’m satisfied with the result. I especially like the functional programming style.