Power of PowerShell and the SharePoint Snap-in

Recently I started to look into some more detail at PowerShell and the SharePoint 2010 Snap-in. As a small exercise I wanted to create something (somewhat) usefull. I came up with a small site structure install script for SP2010. First the source configuration, an xml, with the sites and subsites I wanted to created:

 <?xml version="1.0" ?>
<site title="Test Portal" template="STS#0" lcid="1033" owner="sp2010\administrator">
 <features>
 <feature id="{22a9ef51-737b-4ff2-9346-694633fe4416}"/>
 <feature id="{f6924d36-2fa8-4f0b-b16d-06b7250180fa}"/>
 <feature id="{94c94ca6-b32f-4da9-a9e3-1f3d343d7ecb}"/>
 </features>
 <webs>
  <web url="Subsite1" title="Subsite 1" template="STS#0" lcid="1033" />
  <web url="Subsite2" title="Subsite 2" template="STS#0" lcid="1033">
   <webs>
    <web url="SubSubsite1" title="SubSubsite 1" template="STS#0" lcid="1033" />
    <web url="SubSubsite2" title="SubSubsite 2" template="STS#0" lcid="1033" />
   </webs>
  </web>
  <web url="Subsite3" title="Subsite 3" template="STS#0" lcid="1033">
   <webs>
    <web url="SubSubsite1" title="SubSubsite 1" template="STS#0" lcid="1033" />
    <web url="SubSubsite2" title="SubSubsite 2" template="STS#0" lcid="1033" />
   </webs>
  </web>
 </webs>
</site>

Next I wrote two helper function inside my PowerShell script:

 function ActivateFeatures([System.Xml.XmlNode]$node){
 #features for current web
 $features = $node.selectnodes("./features/feature") # XPath is case sensitive
 foreach ($feature in $features) {
 $fid= $feature.getAttribute("id")
 write-host -f blue "Activating Feature $fid at $baseurl"
 Enable-SPFeature -Identity "$fid" -Url $baseurl -Force
 }
}

function ParseNode([System.Xml.XmlNode]$node){
 $url = $node.getAttribute("url")
 $title = $node.getAttribute("title")
 $lcid = $node.getAttribute("lcid")
 $template = $node.getAttribute("template")
 $baseurl = "$baseurl$url"

 write-host -f red "Going to create site at: $baseurl with Title: $title"
 New-SPWeb -Url "$baseurl" -Name $title -Template $template -Language $lcid

 ActivateFeatures($node);

 # add a trailing slash to create urls
 $baseurl = "$baseurl/"

 # sub webs
 $subnodes = $node.selectnodes("./webs/web") # XPath is case sensitive
 foreach ($subnode in $subnodes) {
 ParseNode($subnode)
 }
}

First remove the existing site collection:

 $baseurl ="https://portal.sp2010.com"
Write-Host -f Red "Removing Site Collection at $baseurl"
Remove-SPSite $baseurl

And then start reading the xml file and start creating a site collection

 write-host -f green "Opening sites.xml"

[System.Xml.XmlDocument] $xd = new-object System.Xml.XmlDocument
$file = resolve-path("./sites.xml")

$xd.Load($file)

#site collection
$sitenode = $xd.selectsinglenode("/site") # XPath is case sensitive
$title = $sitenode.getAttribute("title")
$lcid = $sitenode.getAttribute("lcid")
$template = $sitenode.getAttribute("template")
$owner = $sitenode.getAttribute("owner")

write-host -f red "Creating Site Collection at $baseurl"
New-SPSite -Url "$baseurl" -Name $title -Template $template -Language $lcid -OwnerAlias $owner
ActivateFeatures($sitenode);

# add a trailing slash to create urls
$baseurl = "$baseurl/"

# subwebs
$nodelist = $xd.selectnodes("/site/webs/web") # XPath is case sensitive
foreach ($node in $nodelist) {
    ParseNode($node)
}

write-host "End of sites.xml"

And add this to the top of your SP2010 PowerShell Script to always load the Snap-in.

 $snapin="Microsoft.SharePoint.PowerShell"
if (get-pssnapin $snapin -ea "silentlycontinue") {
    write-host -f Green "PSsnapin $snapin is loaded"
}
elseif (get-pssnapin $snapin -registered -ea "silentlycontinue") {
    write-host -f Green "PSsnapin $snapin is registered"
    Add-PSSnapin $snapin
    write-host -f Green "PSsnapin $snapin is loaded"
}
else {
    write-host -f orange "PSSnapin $snapin not found" -foregroundcolor Red
}

You can download both files here: codeplex.com