Upgrade multiple SharePoint content databases using PowerShell and XML


As a SharePoint Consultant, a lot of the work I do is around upgrades and migrations. I’ve done quite a few of these, and I’ve done them from 2003 to 2007, 2007 to 2010, and now 2010 to 2013. I’ve done several migrations where a 3rd party tool was used to migrate the content, but a lot of the time I end up using the standard database attach approach to move the content databases from the old farm to the new farm. In doing so, obviously PowerShell is required – but more times than not there are multiple content databases. Manually testing and mounting each one can be extremely time consuming, especially if you’re going to end up deploying the content to multiple farms (Dev, QA, DR, Production). What I’ve decided to do is actually build some PowerShell and XML that can be used both to run Test-SPContentDatabase as well as Mount-SPContentDatabase to allow you to do these in bulk.

When writing this script, I had a few things in mind that I wanted to accomplish:

  1. Provide 100% of the input to the script in the form of XML, allowing the script to be 100% separate from the parameters and input.
  2. Provide options to use Test OR Mount, depending on where I’m at in the migration. (It’s always recommended to run Test-SPContentDatabase BEFORE Mount-SPContentDatabase!)
  3. Provide readable output and progress indication to know where the script is in it’s execution.

To accomplish these 3 goals, I made sure to:

  • Include ALL of the available options when running Test-SPContentDatabase AND Mount-SPContentDatabase in the XML and Script (empty values are simply ignored).
  • Include SWITCH parameters for Test and Mount – to allow the user to specify their intention at runtime.
  • Include Write-Progress and Write-Output to provide clear output to the executing user.

Now that I’ve explained my intentions with writing this code, I’ll share it!

Here is an example of how you could use the XML:

<?xml version="1.0" encoding="utf-8" ?>
<WebApps>
	<WebApp Url="http://portal.adventureworks.com">
		<Databases>
			<Database Name="SP2010_Pub_Content_1" WarningSiteCount="0" MaxSiteCount="1" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Publishing" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
			<Database Name="SP2010_Pub_Content_2" WarningSiteCount="5" MaxSiteCount="10" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Publishing" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
		</Databases>
	</WebApp>
	<WebApp Url="http://collab.adventureworks.com">
		<Databases>
			<Database Name="SP2010_Collab_Content_1" WarningSiteCount="25" MaxSiteCount="30" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Collab" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
			<Database Name="SP2010_Collab_Content_2" WarningSiteCount="50" MaxSiteCount="100" AssignNewDatabaseId="false" ChangeSyncKnowledge="false" ClearChangeLog="false" DatabaseCredentials="" DatabaseServer="SPSQL\Collab" NoB2BSiteUpgrade="false" SkipIntegrityChecks="false"/>
		</Databases>
	</WebApp>
</WebApps>

Here is the PowerShell code:

<#
.Synopsis
    This script leverages an XML file as the input - and based on the XML contents will attach one or more 
	content databases to one or more SharePoint 2010/2013 Web Applications.
.Description
    This PowerShell Script uses Get-Content, ForEach-Object and Mount-SPContentDatabase cmdlets along with 
	some other various code snippets to iterate through one or more web applications.
    While attaching content databases to a SharePoint 2010/2013 farm, it will use Write-Progress to provide an update in the PowerShell window.
.Example
    Mount-SPContentDatabasesFromXml.ps1 -XmlInput C:\ContentDatabases.xml
   
    This example will mount all content databases to all web applications specified in an XML file at C:\ContentDatabases.xml.
   
    Example XML syntax:
    <?xml version="1.0" encoding="utf-8" ?>
    <WebApps>
        <WebApp Url="http://igs">
            <Databases>
                <Database Name="SP2010_Content_1" WarningLevel="5" MaxSites="10"/>
                <Database Name="SP2010_Content_2" WarningLevel="50" MaxSites="100"/>
            </Databases>
        </WebApp>
    </WebApps>
.Notes
    Name: Mount-SPContentDatabasesFromXml.ps1
    Author: Ryan Dennis
    Last Edit: 9/16/2013
    Keywords: Mount-SPContentDatabase, ForEach-Object, Get-Content, SharePoint Upgrade/Migration
.Link
    http://www.sharepointryan.com
    ryan@sharepointryan.com
    http://twitter.com/sharepointryan   
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$XmlInput,
[Parameter(Mandatory=$false,ParameterSetName="Test")][Switch]$Test,
[Parameter(Mandatory=$false,ParameterSetName="Mount")][Switch]$Mount
)
# Look for the SharePoint Snapin and add it if not already added #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell) -eq $null)
{
    Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
}
$FarmVersion = (Get-SPFarm).BuildVersion
if ($FarmVersion.Major -eq '15') {$FarmVersion = "2013"} 
elseif ($FarmVersion.Major -eq '14') {$FarmVersion = "2010"} 
else {$FarmVersion = ""}

# Load XML document #
[System.Xml.XmlDocument]$xml = Get-Content $($XmlInput)
if ($xml -eq $null)
{
    throw "XML input not found"
}

# Iterate through each WebApps.WebApp in the XML document and mount databases #
$i=0
$dbCount = $xml.GetElementsByTagName("Database").Count
$xml.WebApps.WebApp | ForEach-Object {
$waUrl = $_.Url

    $_.Databases.Database | ForEach-Object {
        $dbName = $_.Name
		if (!([string]::IsNullOrEmpty($_.WarningSiteCount)))
		{$paramWarningSites = @{WarningSiteCount = $_.WarningSiteCount}}
		else{$paramWarningSites = ""}
		
		if (!([string]::IsNullOrEmpty($_.MaxSiteCount)))
		{$paramMaxSites = @{MaxSiteCount = $_.MaxSiteCount}}
		else{$paramMaxSites = ""}
		
		if (!([string]::IsNullOrEmpty($_.AssignNewDatabaseId)))
		{$paramNewDbId = @{AssignNewDatabaseId = $true}}
		else{$paramNewDbId = ""}
		
		if (!([string]::IsNullOrEmpty($_.ChangeSyncKnowledge)))
		{$paramChangeSync = @{ChangeSyncKnowledge = $true}}
		else{$paramChangeSync = ""}
		
		if (!([string]::IsNullOrEmpty($_.ClearChangeLog)))
		{$paramClearLog = @{ClearChangeLog = $true}}
		else{$paramClearLog = ""}
		
		if (!([string]::IsNullOrEmpty($_.DatabaseCredentials)))
		{$paramDbCreds = (Get-Credential -Message "Enter Database Credentials")}
		else{$paramDbCreds = ""}
		
		if (!([string]::IsNullOrEmpty($_.DatabaseServer)))
		{
			if($Test){
				$paramDbServer = @{ServerInstance = $_.DatabaseServer}
			}
			if($Mount){
				$paramDbServer = @{DatabaseServer = $_.DatabaseServer}
			}
		}
		else{$paramDbServer = ""}
				
		if (!([string]::IsNullOrEmpty($_.NoB2BSiteUpgrade)))
		{$paramNoB2B = @{NoB2BSiteUpgrade = $true}}
		else{$paramNoB2B = ""}
		
		if (!([string]::IsNullOrEmpty($_.SkipIntegrityChecks)))
		{$paramSkipChecks = @{SkipIntegrityChecks = $true}}
		else{$paramSkipChecks = ""}
		
        try
        {
            $i++
            # If Mount switch param is included, mount the databases #
            if($Mount){
				Write-Progress -Activity "Mounting $dbName to web application $($waUrl)" -PercentComplete ($i/$dbCount*100) -Status "Mounting content databases to SharePoint $FarmVersion"
				Mount-SPContentDatabase -Name $dbName -WebApplication $waUrl @paramNewDbId @paramChangeSync @paramClearLog @paramDbCreds @paramDbServer @paramMaxSites @paramNoB2B @paramSkipChecks @paramWarningSites
        	}
			# If Test switch param is included, test the databases #
			if($Test){
				Write-Progress -Activity "Testing $dbName" -PercentComplete ($i/$dbCount*100) -Status "Testing content databases with SharePoint $FarmVersion"
				Write-Output "::Performing operation Test-SPContentDatabase on database: $dbName`n"
				Test-SPContentDatabase -Name $dbName -WebApplication $waUrl @paramDbCreds @paramDbServer
			}
		}
        catch
        {
            Write-Error $_
        }
    } #endDbForEach
} #endForEach

SharePoint Saturday Austin 2013


Today I spoke in front of a great crowd at SharePoint Saturday Austin, which was an all-around blast!

The presentation was about PowerShell (shocker, right?) – but this time had a different vibe as I modified one of my presentations to work in SharePoint 2013 – and I also utilized PowerShell Web Access in Google Chrome for 100% of the technical demonstrations.

Below is a description of the topic itself along with PowerPoint Slides and the PowerShell and XML code that was used in the demo:

The Power is in the Shell, use it wisely!

The topic: The Power is in the Shell, use it wisely!
The story: You may have heard of PowerShell, but do you know what it’s capable of? Gone are the days of long, painful STSADM batch files – we have Windows PowerShell, and it’s here to stay.Learn how you can use Windows PowerShell both to perform simple one-off tasks as well as complex, bulk operations. Leveraging the Object Model gives Administrators and Developers the ability to do in a few lines of code what would’ve taken a lot more work (and probably a Developer or two) in the WSS platform.

In this demo filled session, you’ll see how you can get started with PowerShell, and you will hopefully leave with not only a greater understanding of what PowerShell is – but what it is capable of and how you can start using it to automate tasks in your SharePoint 2010 or 2013 environment.

Here are my slides, and below are the code snippets:

PowerShell code:

Demo 1

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$Template = Get-SPWebTemplate BLANKINTERNETCONTAINER`#0
$Url = "http://sp2013.spsatx.adventureworks.com"
$Site = Get-SPSite $Url
$Site = New-SPSite $Url -OwnerAlias adventureworks\rdennis -Template $Template
$Web = $Site.RootWeb
$web | Get-Member -MemberType property</em></em></em>
$Web.Title = "SharePoint Saturday - Austin, TX"
$Web.Update()
$Web.Dispose()
$Site.Dispose()

Demo 2

function Set-SPWebTitle {
<#
.Synopsis
	Use Set-SPWebTitle to update the Title of a SharePoint Web.
.Description
	This function uses SharePoint Cmdlets and Object Model code to set the title property of a SharePoint Web.
.Example
	C:\PS>Set-SPWebTitle -WebUrl http://<siteUrl> -Title "New Title"
    This example updates the title of a web at http://<siteUrl> to "New Title"
.Notes
	Name: Set-SPWebTitle
	Author: Ryan Dennis
	Last Edit: 2/24/2013
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$WebUrl,
[Parameter(Mandatory=$true)][System.String]$Title
)
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$Web = Get-SPWeb $WebUrl
$Web.Title = $Title
$Web.Update()
$Web.Dispose()
}

Demo 3

function New-SPWebFromXml {
<#
.Synopsis
	Use this PowerShell Script to create lots of sites, very quickly!
.Description
	This advanced function uses Get-Content, ForEach-Object and New-SPWeb 
	cmdlets to bulk create SharePoint webs from an XML file.
.Example
	C:\PS>New-SPWebFromXml -Url http://<siteUrl> -XmlInput c:\Sites.xml
	This example creates sites from an XML located at c:\Sites.xml under a site 
	collection at http://<siteUrl>. 
.Notes
	Name: New-SPWebFromXml
	Author: Ryan Dennis
	Last Edit: 2/24/2013
	Keywords: New-SPWeb, Get-Content, ForEach-Object, New-Timespan, XML
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$Url,
[Parameter(Mandatory=$true)][System.String]$XmlInput
)
Clear-Host

# If SharePoint Snapin isn't loaded - load it #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell)-eq $null)
{
	Write-Host "Adding SharePoint Snapin"
	Add-PSSnapin Microsoft.SharePoint.PowerShell
}
$i=0
do {

# Read in list of sites from XML file #
[xml]$SitesXml = Get-Content $($XmlInput)
if ($SitesXml -eq $null) { return }

$siteCount = $SitesXml.Sites.Site.Count
Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
-Status "Retrieving XML Data" -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2

Start-SPAssignment -Global

# Loop through each site node to extract data #
$SitesXml.Sites.Site | ForEach-Object {
    $SiteTitle = [string]$_.SiteTitle
	$SiteUrl = [string]$_.SiteUrl
    Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
    -Status "Creating an SPWeb at $($SiteUrl)" -ErrorAction SilentlyContinue
	$i++
	# Site specifics # 
	$WebTemplate = "BLANKINTERNET`#0"
	$LangId = "1033"
	$SiteUrl = $Url+$SiteUrl
	# Create the SPWeb #
	if ($_.create -ne "false")
	{
	$Web = New-SPWeb -Url $SiteUrl -Language $LangId -Template $WebTemplate `
	-Name $SiteTitle
	}
	else
	{
	$Web = Get-SPWeb -Identity $SiteUrl
	}
	# Get publishing site and web objects
	$site = $web.Site
	$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
	$pagesLib = $pWeb.PagesList

    # Enable moderation on Pages libraries #
	$pagesLib.EnableModeration = $true;
	$pagesLib.EnableMinorVersions = $true;
	$pagesLib.Update()	

	# Create all Pages using ForEach-Object #
	if ($_.Page -ne $null){
	$pages = $_.Page | ForEach-Object {
	
	# Create page content variables from XML file
	$PageTitle = [string]$_.PageTitle
	$PageUrl = [string]$_.PageUrl
	$PageLayout = [string]$_.PageLayout
	$PageContent = [string]$_.PageContent
	$PageImage = [string]$_.PageImage
	$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
	
    # Create blank page using Add method
	Write-Progress -Activity "Provisioning SharePoint Webs from XML" -PercentComplete (($i/$siteCount) * 100) `
    -Status "Creating $($PageTitle).aspx page" -ErrorAction SilentlyContinue
    $pages = $pWeb.GetPublishingPages($pWeb)
	$page = $pages.Add($PageUrl, $layout)
	$page.Update()
	
    # Update the filename to the one specified in the XML, add HTML content to Page Content zone
    $item = $page.ListItem
	$item["Title"] = $PageTitle;
	$item.Update()
	
   	# Check-in and publish page
    $item.File.CheckIn("")
    $item.File.Publish("")
	$item.File.Approve("")
	$file = $item.File
	# If the page is marked as the Home Page in XML, set it as welcome page #
	if($_.IsHomePage -eq "true"){
	$pWeb.DefaultPage = $file
	}
	$pWeb.Update()
	
	} #end Page Foreach
	
	} # End if block #
	
} # End ForEach-Object loop #
} while ($i -lt $siteCount)
} # End function

XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<Sites>
  <SiteAdmins>
    <User>adventureworks\rdennis</User>
    <User>adventureworks\spfarm</User>
  </SiteAdmins>
  <!-- root site -->
  <Site Create="false">
    <SiteTitle>Home</SiteTitle>
    <SiteUrl>/</SiteUrl>
		<Page IsHomePage="false">
		  <PageTitle>Intranet Governance</PageTitle>
		  <PageUrl>Intranet-Governance.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Terms of Use</PageTitle>
		  <PageUrl>Terms-of-Use.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Privacy Policy</PageTitle>
		  <PageUrl>Privacy-Policy.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Linking Policy</PageTitle>
		  <PageUrl>Linking-Policy.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Legal Disclaimer</PageTitle>
		  <PageUrl>Legal-Disclaimer.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Help Me</PageTitle>
		  <PageUrl>Help-Me.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <!-- 2nd level sites -->
  <Site>
    <SiteTitle>My Company</SiteTitle>
    <SiteUrl>/My-Company</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>My Company</PageTitle>
		  <PageUrl>My-Company.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Our Culture</PageTitle>
		  <PageUrl>Our-Culture.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>History and Timeline</PageTitle>
		  <PageUrl>History-And-Timeline.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Sustainability</PageTitle>
		  <PageUrl>Sustainability.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>My Community</PageTitle>
		  <PageUrl>My-Community.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Our Customers</SiteTitle>
    <SiteUrl>/Our-Customers</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Our Customers</PageTitle>
		  <PageUrl>Our-Customers.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Customer Engagement</PageTitle>
		  <PageUrl>Customer-Engagement.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Employee Ambassadors</PageTitle>
		  <PageUrl>Employee-Ambassadors.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>News and Info</SiteTitle>
    <SiteUrl>/News-And-Info</SiteUrl>
		<Page IsHomePage="false">
		  <PageTitle>Utility Performance</PageTitle>
		  <PageUrl>Utility-Performance.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>News Archive</PageTitle>
		  <PageUrl>News-Archive.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Calendar</PageTitle>
		  <PageUrl>Calendar.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Social Media</PageTitle>
		  <PageUrl>Social-Media.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Task Center</SiteTitle>
    <SiteUrl>/Task-Center</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Task Center</PageTitle>
		  <PageUrl>Task-Center.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Travel</PageTitle>
		  <PageUrl>Travel.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Toolbox</PageTitle>
		  <PageUrl>Toolbox.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Managing Employees</PageTitle>
		  <PageUrl>Managing-Employees.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
  <Site>
    <SiteTitle>Collaboration</SiteTitle>
    <SiteUrl>/Collaboration</SiteUrl>
		<Page IsHomePage="true">
		  <PageTitle>Collaboration</PageTitle>
		  <PageUrl>Collaboration.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Communities</PageTitle>
		  <PageUrl>Communities.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
		<Page IsHomePage="false">
		  <PageTitle>Employee Surveys</PageTitle>
		  <PageUrl>Employee-Surveys.aspx</PageUrl>
		  <PageLayout>Blank Web Part Page</PageLayout></Page>
  </Site>
</Sites>

Dog Food Conference 2012


This morning (and afternoon) I spoke in front of a great crowd at the Dog Food Conference in Columbus, Ohio.

I chose to re-use my Build your SharePoint Internet presence with PowerShell presentation, as I still think it’s a good presentation that gives a good introductory view into how you can automate site provisioning with PowerShell. I also try to keep it light from a technical standpoint and tend to focus more on the business case around using PowerShell as an automation tool.

Below is a description of the topic itself along with PowerPoint Slides and the PowerShell and XML code that was used in the demo:

Build your SharePoint Internet presence with PowerShell

The topic: Build your SharePoint Internet presence with PowerShell
The story: Everybody knows PowerShell is powerful, it’s in the name! But did you know that PowerShell can read and understand XML? By leveraging XML among other things, complete builds can be automated – making them efficient and predictable.

In this fun, interactive and demo-filled session – I will show you how you can leverage PowerShell to help you build your branded, company website from the ground up using PowerShell and XML. I will also pass along some tips and tricks that will help you become a PowerShell Rockstar!

Here are my slides, and below are the code snippets:

Demo Script – Setup-SPWebAppAndSite.ps1

Config XML Syntax:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;WebApplications&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;AdventureWorks.com&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - AdventureWorksDemoWeb&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_AdventureWorks_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;www.adventureworks.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http&lt;/Protocol&gt;
			&lt;ManagedPaths&gt;
				&lt;ManagedPath Type=&quot;explicit&quot; Path=&quot;search&quot;/&gt;
			&lt;/ManagedPaths&gt;
			&lt;Solutions&gt;
				&lt;Solution GACDeployment=&quot;true&quot;&gt;adventureworks_site_branding.wsp&lt;/Solution&gt;
			&lt;/Solutions&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\AdventureWorks.com&lt;/BlobCacheLocation&gt;
			&lt;Authentication&gt;
				&lt;!--Auth Types - Claims,Classic--&gt;
				&lt;Type&gt;Classic&lt;/Type&gt;
				&lt;!--Auth Methods - NTLM,Kerberos--&gt;
				&lt;AuthMethod&gt;NTLM&lt;/AuthMethod&gt;
				&lt;AuthProvider Name=&quot;&quot; 
				MembershipProviderName=&quot;&quot; 
				RoleProviderName=&quot;&quot; 
				/&gt;
			&lt;/Authentication&gt;
		&lt;/WebAppConfig&gt;
		&lt;SiteCollections&gt;
			&lt;SiteCollection&gt;
				&lt;Name&gt;AdventureWorks.com&lt;/Name&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
				&lt;Path&gt;/&lt;/Path&gt;
				&lt;Features&gt;
					&lt;Feature&gt;BaseSite&lt;/Feature&gt;
					&lt;Feature&gt;BaseWeb&lt;/Feature&gt;
					&lt;Feature&gt;PremiumSite&lt;/Feature&gt;
					&lt;Feature&gt;PremiumWeb&lt;/Feature&gt;
					&lt;Feature&gt;TeamCollab&lt;/Feature&gt;
					&lt;!--&lt;Feature&gt;a6ad433b-0bdf-40aa-aec8-6a091d7a3c26&lt;/Feature&gt;--&gt;
					&lt;Feature&gt;1caa8e30-f360-4ebc-a38e-e57708109e6f&lt;/Feature&gt;
				&lt;/Features&gt;
				&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
				&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
				&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
				&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
				&lt;SearchSettings&gt;
					&lt;SearchCenterUrl&gt;/search/pages&lt;/SearchCenterUrl&gt;
					&lt;!-- Possible dropdown values are--&gt;
					&lt;!--
					HideScopeDD_DefaultContextual
					HideScopeDD
					ShowDD
					ShowDD_DefaultURL
					ShowDD_DefaultContextual
					ShowDD_NoContextual
					ShowDD_NoContextual_DefaultURL
					--&gt;
					&lt;DropDownMode&gt;ShowDD&lt;/DropDownMode&gt;
					&lt;TargetResultsPage&gt;/search/pages/results.aspx&lt;/TargetResultsPage&gt;
				&lt;/SearchSettings&gt;
			&lt;/SiteCollection&gt;
			&lt;SiteCollection&gt;
				&lt;Name&gt;Search Center&lt;/Name&gt;
				&lt;WebTemplate&gt;SRCHCEN#0&lt;/WebTemplate&gt;
				&lt;Path&gt;/search&lt;/Path&gt;
				&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
				&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
				&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
				&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;/SiteCollection&gt;
		&lt;/SiteCollections&gt;
		&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;Contoso Extranet&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;extranet.contoso.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
		&lt;Sites&gt;
			&lt;!-- root site --&gt;
			&lt;Site Create=&quot;false&quot;&gt;
				&lt;SiteTitle&gt;Home&lt;/SiteTitle&gt;
				&lt;SiteUrl&gt;http://www.adventureworks.com/&lt;/SiteUrl&gt;
				&lt;Page&gt;
				   &lt;PageTitle&gt;Home&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Home.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;	
				&lt;Page&gt;
				   &lt;PageTitle&gt;Terms of Use&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Terms-of-Use.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;
				&lt;Page&gt;
				   &lt;PageTitle&gt;Privacy Policy&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Privacy-Policy.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;
				&lt;Page&gt;
				   &lt;PageTitle&gt;Linking Policy&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Linking-Policy.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;
				&lt;Page&gt;
				   &lt;PageTitle&gt;Legal Disclaimer&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Legal-Disclaimer.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;	
				&lt;Page&gt;
				   &lt;PageTitle&gt;404 - Page Not Found&lt;/PageTitle&gt;
				   &lt;PageUrl&gt;Page-Not-Found.aspx&lt;/PageUrl&gt;
				   &lt;PageContent&gt;&lt;/PageContent&gt;
				   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			   &lt;/Page&gt;			   		   
			&lt;/Site&gt;		
		&lt;/Sites&gt;
	&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;Contoso Intranet&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;intranet.contoso.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
	&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;Contoso Website&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;www.contoso.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
	&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;AdventureWorks Intranet&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;intranet.adventureworks.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
	&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;AdventureWorks Extranet&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;extranet.adventureworks.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
	&lt;/WebApplication&gt;
	&lt;WebApplication&gt;
		&lt;WebAppConfig&gt;
			&lt;Name&gt;My Sites&lt;/Name&gt;
			&lt;AppPool&gt;SharePoint - ContosoDemo&lt;/AppPool&gt;
			&lt;AppPoolAccount&gt;ISG1085\SpAppPool&lt;/AppPoolAccount&gt;
			&lt;DBServer&gt;ISG1085\SharePoint&lt;/DBServer&gt;
			&lt;DBName&gt;SP2010_Content_Contoso_Demo&lt;/DBName&gt;
			&lt;HostHeader&gt;mysites.adventureworks.com&lt;/HostHeader&gt;
			&lt;InetpubPath&gt;C:\inetpub\wwwroot\wss\VirtualDirectories&lt;/InetpubPath&gt;
			&lt;Port&gt;80&lt;/Port&gt;
			&lt;Protocol&gt;http://&lt;/Protocol&gt;
			&lt;OwnerAlias&gt;ISG1085\SharePointRyan&lt;/OwnerAlias&gt;
			&lt;OwnerEmail&gt;SharePointRyan@demowebsite.com&lt;/OwnerEmail&gt;
			&lt;SecondaryOwnerAlias&gt;ISG1085\SPFarm&lt;/SecondaryOwnerAlias&gt;
			&lt;SecondaryOwnerEmail&gt;SPFarm@demowebsite.com&lt;/SecondaryOwnerEmail&gt;
			&lt;RootSite&gt;
				&lt;WebTemplate&gt;BLANKINTERNET#0&lt;/WebTemplate&gt;
			&lt;/RootSite&gt;
			&lt;BlobCacheLocation&gt;C:\SharePointBlobCache\Contoso.com&lt;/BlobCacheLocation&gt;
		&lt;/WebAppConfig&gt;
	&lt;/WebApplication&gt;
&lt;/WebApplications&gt;

Subsite XML Syntax:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;SubSites&gt;
	&lt;Sites SPSiteUrl=&quot;http://www.adventureworks.com&quot;&gt;
		&lt;!-- root site --&gt;
		&lt;Site Create=&quot;false&quot;&gt;
			&lt;SiteTitle&gt;Home&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Home&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Home.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;	
			&lt;Page&gt;
			   &lt;PageTitle&gt;Terms of Use&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Terms-of-Use.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Privacy Policy&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Privacy-Policy.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Linking Policy&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Linking-Policy.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Legal Disclaimer&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Legal-Disclaimer.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;	
			&lt;Page&gt;
			   &lt;PageTitle&gt;404 - Page Not Found&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Page-Not-Found.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
		   &lt;/Page&gt;			   		   
		&lt;/Site&gt;		
		&lt;!-- 2nd level sites --&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Products&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Products&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Awesome Widget&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Awesome-Widget.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;The Spectacular Thingamajig&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;The-Spectacular-Thingamajig.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Store&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Store.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Solutions&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Solutions&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Customer Engagement&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Customer-Engagement.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Custom Solutions&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Custom-Solutions.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Shipping and Returns&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Shipping-and-Returns&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Shipping Policies&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Shipping-Policies.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Return Policies&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Return-Policies.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;About Us&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/About-Us&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Company&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Company.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;History&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;History.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Locations&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Locations.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Blank Web Part page&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Employment Opportunities&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Employment-Opportunities.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Contact Us&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Contact-Us&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Social Media&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Social-Media.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Locations&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Locations.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Service Requests&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Service-Requests.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Request a Catalog&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Request-a-Catalog.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Our Company&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Our-Company&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Forms&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Forms.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
			&lt;Page&gt;
			   &lt;PageTitle&gt;Travel&lt;/PageTitle&gt;
			   &lt;PageUrl&gt;Travel.aspx&lt;/PageUrl&gt;
			   &lt;PageContent&gt;&lt;/PageContent&gt;
			   &lt;PageLayout&gt;Body Only&lt;/PageLayout&gt;
			&lt;/Page&gt;
		&lt;/Site&gt;
		&lt;Site&gt;
			&lt;SiteTitle&gt;Our Customers&lt;/SiteTitle&gt;
			&lt;SiteUrl&gt;http://www.adventureworks.com/Our-Customers&lt;/SiteUrl&gt;
			&lt;WebTemplate&gt;CMSPUBLISHING#0&lt;/WebTemplate&gt;
			&lt;LangId&gt;1033&lt;/LangId&gt;
		&lt;/Site&gt;
	&lt;/Sites&gt;
&lt;/SubSites&gt;

PowerShell code:

#Region New-SPWebApplicationFromXml
function New-SPWebApplicationFromXml {
&lt;#
.Synopsis
	This advanced PowerShell Function uses XML and PowerShell code to provision
	one or more Web Applications, Site Colections, Subsites and Pages. It can 
	also deploy and activate solutions and features.
.Description
	This advanced script uses New-SPWebApplication, New-SPSite and 
	Enable-SPFeature to configure web applications and site collections using
	specified Site Templates from the included XML. Features, Managed Paths, 
	subsites and even Publishing pages can be created using XML as the input.
.Example
	C:\PS&gt;New-SPWebApplicationFromXml -ConfigXmlInput .\WebApps.xml `
	-SubsiteXmlInput .\Subsites.xml
	
	This example runs with the default parameter values to configure a Web App
	and Site Collection based on the contents of an XML file called 
	WebApps.xml in the current file directory.
.Notes
	Name: New-SPWebApplicationFromXml
	Author: Ryan Dennis
	Last Edit: 9/7/2012
	Keywords: New-SPWebApplication, New-SPSite
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
#Requires -Version 2.0
#&gt;
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$ConfigXmlInput,
[Parameter(Mandatory=$true)][System.String]$SubsiteXmlInput
)

#Region Miscellaneous stuff at the beginning
# If SharePoint Snapin isn't loaded - load it #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell)-eq $null)
{
	Write-Warning &quot;Adding SharePoint Snapin&quot;
	try	{ Add-PSSnapin Microsoft.SharePoint.PowerShell }
	catch { throw &quot;Unable to add SharePoint Snapin&quot;;return }
}
# Start SP Assignment for proper disposal of objects such as SPSite and SPWeb #
Start-SPAssignment -Global

# Read Web Apps from XML file #
[xml]$WebAppXml = Get-Content $($ConfigXmlInput)
if ($WebAppXml -eq $null) { return }

[xml]$SubsiteXml = Get-Content $($SubsiteXmlInput)
if ($SubsiteXml -eq $null) { return }


#EndRegion

#Region Enable Blob Cache function 
function Enable-SPBlobCache { 
param( 
	[Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
	[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind] 
	$WebApplication,
	[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=1)]
	$BlobCacheLocation=&quot;C:\BlobCache\14&quot;
) 

process { 
    $WebApp = $WebApplication.Read() 
    # SPWebConfigModification to enable BlobCache 
    $configMod1 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification 
    $configMod1.Path = &quot;configuration/SharePoint/BlobCache&quot; 
    $configMod1.Name = &quot;enabled&quot; 
    $configMod1.Sequence = 0 
    $configMod1.Owner = &quot;BlobCacheMod&quot; 
    ## SPWebConfigModificationType.EnsureChildNode -&gt; 0 
    ## SPWebConfigModificationType.EnsureAttribute -&gt; 1 
    ## SPWebConfigModificationType.EnsureSection -&gt; 2 
    $configMod1.Type = 1 
    $configMod1.Value = &quot;true&quot;
		
    ######################################################################
	
	# SPWebConfigModification to enable client-side Blob caching (max-age) 
    $configMod2 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification 
    $configMod2.Path = &quot;configuration/SharePoint/BlobCache&quot; 
    $configMod2.Name = &quot;max-age&quot; 
    $configMod2.Sequence = 0 
    $configMod2.Owner = &quot;BlobCacheMod&quot; 
    ## SPWebConfigModificationType.EnsureChildNode -&gt; 0 
    ## SPWebConfigModificationType.EnsureAttribute -&gt; 1 
    ## SPWebConfigModificationType.EnsureSection -&gt; 2 
    $configMod2.Type = 1 
    $configMod2.Value = &quot;86400&quot; 
	
	######################################################################
	
	# SPWebConfigModification to change the default location for the Blob Cache files
	$configMod3 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
	$configMod3.Path = &quot;configuration/SharePoint/BlobCache&quot;
	$configMod3.Name = &quot;location&quot;
	$configMod3.Sequence = &quot;0&quot;
	$configMod3.Owner = &quot;BlobCacheMod&quot;
	## SPWebConfigModificationType.EnsureChildNode -&gt; 0 
    ## SPWebConfigModificationType.EnsureAttribute -&gt; 1 
    ## SPWebConfigModificationType.EnsureSection -&gt; 2 
	$configMod3.Type = 1
	$configMod3.Value = $BlobCacheLocation
    # Add mods, update, and apply 
    $WebApp.WebConfigModifications.Add( $configMod1 ) 
    $WebApp.WebConfigModifications.Add( $configMod2 )
	$WebApp.WebConfigModifications.Add( $configMod3 )
    $WebApp.Update() 
    $WebApp.Parent.ApplyWebConfigModifications() 
} 
}

#EndRegion Blob Cache Function

#Region New-BalloonTip Function
function New-BalloonTip {
[CmdletBinding()]
Param(
$TipText='This is the body text.',
$TipTitle='This is the title.',
$TipDuration='10000'
)
[system.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null
$balloon = New-Object System.Windows.Forms.NotifyIcon
$path = Get-Process -id $pid | Select-Object -ExpandProperty Path
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.Icon = $icon
$balloon.BalloonTipIcon = 'Info'
$balloon.BalloonTipText = $TipText
$balloon.BalloonTipTitle = $TipTitle
$balloon.Visible = $true
$balloon.ShowBalloonTip($TipDuration)
}
#EndRegion New-BalloonTipFunction

#Region Load the Form Dialog
# Load Assemblies for System.Windows.Forms and System.Drawing #
[void] [System.Reflection.Assembly]::LoadWithPartialName(&quot;System.Windows.Forms&quot;)
[void] [System.Reflection.Assembly]::LoadWithPartialName(&quot;System.Drawing&quot;) 

# Store the 14 Hive in Variable, create an Img variable for Icon #
$14 = 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14'
$Img = $14+&quot;\Template\Images\Favicon.ico&quot;

# Create the Form Object #
$objForm = New-Object System.Windows.Forms.Form 
$objForm.Text = &quot;SharePoint Web Application Deployment Wizard&quot;
$objForm.Size = New-Object System.Drawing.Size(500,350) 
$objForm.StartPosition = &quot;CenterScreen&quot;
$objForm.Icon = $Img
$objForm.FormBorderStyle = 'FixedDialog'
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq &quot;Enter&quot;) 
    {
		$objForm.DialogResult = [System.Windows.Forms.DialogResult]::OK
		$SelectedApps = $null
		[System.String]$Items=$objListBox.SelectedItems;
		[System.Array]$SelectedApps=$Items.Split(' ');
		if($SelectedApps -eq $null){
		throw &quot;You must select at least one web application!&quot;}
		$objForm.Close()
	}
}
)
$objForm.Add_KeyDown({if ($_.KeyCode -eq &quot;Escape&quot;){$objForm.Close()}})

# OK Button #
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(330,280)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = &quot;OK&quot;
$OKButton.Add_Click(
{
	$objForm.DialogResult = [System.Windows.Forms.DialogResult]::OK
	$SelectedApps = $null
	[System.String]$Items=$objListBox.SelectedItems;
	[System.Array]$SelectedApps=$Items.Split(' ');
	if($SelectedApps -eq $null)
	{
	throw &quot;You must select at least one web application!&quot;
	}
	$objForm.Close()
})

# Cancel Button #
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(405,280)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = &quot;Cancel&quot;
$CancelButton.Add_Click(
{
	$objForm.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
	$objForm.Close()
}
)

# Listbox Object #
$objListBox = New-Object System.Windows.Forms.ListBox 
$objListBox.Location = New-Object System.Drawing.Size(10,40) 
$objListBox.Size = New-Object System.Drawing.Size(470,20) 
$objListBox.Height = 230
$objListBox.SelectionMode = &quot;MultiExtended&quot;

# Listbox Label #
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20) 
$objLabel.Size = New-Object System.Drawing.Size(470,20) 
$objLabel.Text = &quot;Please select the web application(s) you wish to deploy:&quot;

$WebApps = $WebAppXml.WebApplications.WebApplication
$WebApps | ForEach-Object {
	[void] $objListBox.Items.Add($_.WebAppConfig.HostHeader)
}

# Add the controls to the Form Object #
$objForm.Controls.Add($objLabel)
$objForm.Controls.add($objListBox)
$objForm.Controls.Add($OKButton)
$objForm.Controls.Add($CancelButton)
$objForm.Controls.Add($SearchButton)

# Display the form on top of all other windows #
$objForm.Topmost = $True

# Add the dialog box to the screen #
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()

#EndRegion Form Dialog

#Region Web App ForEach-Object Loop to create everything
# If the dialog result is OK, run the code to create navigation #
if ($objForm.DialogResult -eq &quot;OK&quot; -and $SelectedApps -ne $null)
{
$SelectedApps | ForEach-Object {
	
	#Region Create Web Application
	# Clear Host for a clean, empty shell #
	Clear-Host
	
	[System.String]$CurrentWA = $_
	$wa = $WebAppXml.WebApplications.WebApplication |
	Where-Object {$_.WebAppConfig.HostHeader -eq $CurrentWA}
	
	# Store start time in variable for calculation later #
	$StartTime = Get-Date

	# Read in list of sites from XML file and create variables for use later #
	$Name = $wa.WebAppConfig.Name
	$ApplicationPool = $wa.WebAppConfig.AppPool
	$ApplicationPoolAccount = $wa.WebAppConfig.AppPoolAccount
	$DatabaseServer = $wa.WebAppConfig.DBServer
	$DatabaseName = $wa.WebAppConfig.DBName
	$InetpubPath = $wa.WebAppConfig.InetpubPath
	$HostHeader = $wa.WebAppConfig.HostHeader
	$Port = $wa.WebAppConfig.Port
	$WebsitePath=$InetpubPath+&quot;\&quot;+$HostHeader+$Port
	$Protocol = $wa.WebAppConfig.Protocol
	$Url = $Protocol+&quot;://&quot;+$HostHeader+&quot;:&quot;+$Port
	$ManagedPaths = $wa.WebAppConfig.ManagedPaths
	$Solutions = $wa.WebAppConfig.Solutions
	$BlobCacheLocation = $wa.WebAppConfig.BlobCacheLocation
	$AuthType = $wa.WebAppConfig.Authentication.Type
	$AuthMethod = $wa.WebAppConfig.Authentication.AuthMethod
	$AuthProviderName = $wa.WebAppConfig.Authentication.AuthProvider.Name
	$AuthProviderMember = $wa.WebAppConfig.Authentication.AuthProvider.MembershipProviderName
	$AuthProviderRole = $wa.WebAppConfig.Authentication.AuthProvider.RoleProviderName
	
	# Start SP Assignment for object disposal later #
	Start-SPAssignment -Global

	# Change Shell Title #
	$title = $Host.UI.RawUI.WindowTitle
	$Host.UI.RawUI.WindowTitle = &quot;Provisioning Web Application...&quot;

	$ErrorPref = $ErrorActionPreference
	$ErrorActionPreference = &quot;SilentlyContinue&quot;
	$WarningPref = $WarningPreference
	$WarningPreference = &quot;SilentlyContinue&quot;

	# Tell us the Web App is getting created #
	$iMax = 11 #Number of Steps#
	$i = 0 #Number to start on#
	
	$i++ #step 1
	Write-Progress -Activity &quot;Step $i of $iMax : Creating Web Application at Url $($HostHeader)&quot; `
	-PercentComplete ($i/$imax*100) -Status &quot;Creating IIS Website, Content Database and Application Pool&quot;
	# Create a Classic App #
	if($AuthType -eq &quot;Classic&quot;){
		try {
			# Create the Web App #
			New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `
			-ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `
			-DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `
			-Path $WebsitePath -Url $HostHeader -WarningAction SilentlyContinue | Out-Null
			New-BalloonTip -TipText &quot;The web application at Url: $($HostHeader) has been created.&quot; `
			-TipTitle &quot;Web Application created successfully&quot;
		} 
		catch {	throw &quot;Unable to create the web application&quot;;return	}
	}
	# Create a Windows Claims App #
	if($AuthType -eq &quot;Claims&quot;){
		try {
			# Create the auth provider #
			$ap = New-SPAuthenticationProvider
			# Create the Web App #
			New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `
			-ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `
			-DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `
			-Path $WebsitePath -Url $HostHeader -WarningAction SilentlyContinue `
			-AuthenticationProvider $ap -AuthenticationMethod $AuthMethod | Out-Null
		} 
		catch {	throw &quot;Unable to create the web application&quot;;return	}
	}
	#EndRegion Create Web Application
	
	#Region Creating Managed Paths
	$i++ #Step2
	# Create Managed Paths #
	$wa.WebAppConfig.ManagedPaths.ManagedPath | ForEach-Object {
		$path = $_.path
		$type = $_.type
		if($type -eq &quot;explicit&quot;){
			New-SPManagedPath -Explicit -RelativeURL $path -WebApplication $Url `
			-ErrorAction SilentlyContinue | Out-Null
			New-BalloonTip -TipText &quot;The managed path at path: $($path) has been created.&quot; `
			-TipTitle &quot;Managed path created successfully&quot;
		}
		elseif($type -eq &quot;wildcard&quot;){
			New-SPManagedPath -RelativeURL $path -WebApplication $Url `
			-ErrorAction SilentlyContinue | Out-Null
			New-BalloonTip -TipText &quot;The managed path at path: $($path) has been created.&quot; `
			-TipTitle &quot;Managed path created successfully&quot;
		}
	}
	#EndRegion Creating Managed Paths
	
	#Region Installing Solutions
	$i++ #Step3
	# Change Shell Title #
	$Host.UI.RawUI.WindowTitle = &quot;Installing Solutions...&quot;
	# Enable solutions #
	try {
		$Solutions.Solution | ForEach-Object {
		$SolutionId = $_
			if($SolutionId.GACDeployment -eq &quot;true&quot;){
			Write-Progress -Activity &quot;Step $i of $iMax : Installing Solutions...&quot; `
			-PercentComplete ($i/$imax*100) -Status &quot;Activating $($SolutionId) solution&quot;
			Install-SPSolution $($SolutionId) -WebApplication $Url `
			-GACDeployment -ErrorVariable +err -Confirm:$false
			Start-Sleep -Seconds 5
			}
			else{
			Write-Progress -Activity &quot;Step $i of $iMax : Installing Solutions...&quot; `
			-PercentComplete ($i/$imax*100) -Status &quot;Activating $($SolutionId) solution&quot;
			Install-SPSolution $($SolutionId) -WebApplication $Url `
			-ErrorVariable +err -Confirm:$false
			Start-Sleep -Seconds 5
			}
		}
	}
	catch { Write-Error &quot;Error enabling solution $($SolutionId)&quot; }
	#EndRegion Installing Solutions	
		
	#Region Create Site Collections
	# Change Shell Title #
	$Host.UI.RawUI.WindowTitle = &quot;Provisioning Site Collections...&quot;
	$i++ #step4
	$siteCollections = $wa.SiteCollections
	# Create Site Collections using ForEach-Object loop #
	try {
	$SiteCollections.SiteCollection | ForEach-Object {
		$NewSiteUrl = $Url+$_.Path
		$sName = $_.Name
		$sOAlias = $_.OwnerAlias
		$sOEmail = $_.OwnerEmail
		$sSOAlias = $_.SecondaryOwnerAlias
		$sSOEmail = $_.SecondaryOwnerEmail
		$sTemplate = $_.WebTemplate
		$subSites = $_.Sites
		$srchUrl = $_.SearchSettings.SearchCenterUrl
		$srchDD = $_.SearchSettings.DropDownMode
		$srchPage = $_.SearchSettings.TargetResultsPage
		# Tell us the Site Collection is getting created #
		Write-Progress -Activity &quot;Step $i of $iMax : Creating Site Collection at Url $($HostHeader)...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Provisioning $($sTemplate) site&quot;
		$SPSite = New-SPSite -Name $sName -OwnerAlias $sOAlias -OwnerEmail $sOEmail `
		-SecondaryOwnerAlias $sSOAlias -SecondaryEmail $sSOEmail `
		-Template $sTemplate -Url $NewSiteUrl | Out-Null
		New-BalloonTip -TipText &quot;The site collection at Url: $($NewSiteUrl) has been created.&quot; `
		-TipTitle &quot;Site collection created successfully&quot;
		Start-Sleep -Seconds 5
		
		$_.Features.Feature | ForEach-Object {
		# Enable Features #
		try {
			$FeatureId = $_
			Write-Progress -Activity &quot;Step $i of $iMax : Configuring Site Features...&quot; `
			-PercentComplete ($i/$imax*100) -Status &quot;Activating $($FeatureId) feature&quot;
			Enable-SPFeature -Identity $($FeatureId) -Url $NewSiteUrl -ErrorVariable +err `
			-ErrorAction SilentlyContinue -Confirm:$false
			}
		catch { Write-Error &quot;Error activating feature $err&quot; }
		} #end Feature ForEach
		New-BalloonTip -TipText &quot;The specified features have been enabled.&quot; `
		-TipTitle &quot;Features activated successfully&quot;
		Start-Sleep -Seconds 5
		
		
		#Region Search Settings
		.\Set-SPSiteSearchSettings.ps1 -SiteUrl $NewSiteUrl -SearchCenterUrl $srchUrl `
		-SearchDropDownMode $srchDD -SearchResultsUrl $srchPage
		#EndRegion Search Settings
		
	} #End Site Collection ForEach
	} #End Site Collection Try
	catch { throw &quot;Unable to create site collection at path: $NewSiteUrl&quot;;return }
	
	#EndRegion Create Site Collections

	#Region Configure Blob Caching
	$i++ #step 7
	Write-Progress -Activity &quot;Step $i of $iMax : Configuring Cache Settings...&quot; `
	-PercentComplete ($i/$imax*100) -Status &quot;Configuring BLOB Caching&quot;
	try {
	Enable-SPBlobCache -WebApplication $Url -BlobCacheLocation $BlobCacheLocation
	}
	catch { Write-Error &quot;Unable to configure BLOB caching&quot; }
	#EndRegion Configure Blob Caching
	
	#Region Run External Scripts
		$location = Get-Location
		$modPath = $PSHOME+&quot;\Modules\PSSAT002\&quot;
		Set-Location $modPath
	
		#Region Create Web App Policy
		$i++ #step8
		Write-Progress -Activity &quot;Step $i of $iMax : Creating Web Application Policy...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Configuring Full Control Policy&quot;
		
		.\Configure-SPWebApplicationUserPolicy.ps1 -WebApplicationUrl $Url
		#EndRegion Create Web App Policy	
	
		#Region Meta Fields
		# Create Meta Fields #
		$i++ #step 9
		Write-Progress -Activity &quot;Step $i of $iMax : Configuring SEO Fields...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Provisioning SEO Meta Fields&quot;
		
		#Write-Host &quot;Configuring SEO fields&quot;
		.\Create-MaventionMetaFields.ps1 -Url $Url
		#EndRegion MetaFields

		Set-Location $location
	#EndRegion Run External Scripts
	
	#Region Create Subsites
	
		# Create subwebs from XML input #
		$i++ #step 11
		Write-Progress -Activity &quot;Step $i of $iMax : Creating Subsites from XML...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Retrieving sites from XML file&quot;
		Start-SPAssignment -Global
		
		$SubsiteXml.SubSites.Sites.Site | ForEach-Object {
		Write-Progress -Activity &quot;Step $i of $iMax : Creating Subsites from XML...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Creating an SPWeb at $($SiteUrl)&quot;
		$SPSiteUrl = $_.SPSiteUrl
		$SiteTitle = [string]$_.SiteTitle
		$SiteUrl = [string]$_.SiteUrl
		$SiteOwner = [string]$_.Owner
		$SiteUser = [string]$_.User
		$WebTemplate = [string]$_.WebTemplate
		$LangId = [string]$_.LangId
		$SiteUrl = $SiteUrl
		# Create the SPWeb #
		if ($_.create -ne &quot;false&quot;)
		{
		$Web = New-SPWeb -Url $SiteUrl -Language $LangId -Template $WebTemplate `
		-Name $SiteTitle -ErrorAction Inquire
		}
		else {
		$Web = Get-SPWeb -Identity $SiteUrl -ErrorAction Inquire
		}
		# Get publishing site and web objects
		$site = $Web.Site
		$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)

		# Create all Pages using ForEach-Object #
		if ($_.Page -ne $null){
		$_.Page | ForEach-Object {
		
		# Create page content variables from XML file
		$PageTitle = [string]$_.PageTitle
		$PageUrl = [string]$_.PageUrl
		$PageLayout = [string]$_.PageLayout
		#$PageContent = [xml]$_.PageContent
		$PageImage = [string]$_.PageImage
		$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
		
	    # Create blank page using Add method
		Write-Progress -Activity &quot;Step $i of $iMax : Creating Subsites from XML...&quot; `
		-PercentComplete ($i/$imax*100) -Status &quot;Creating $($PageTitle).aspx page in $($SiteTitle) site...&quot;
	    $pages = $pWeb.GetPublishingPages($pWeb)
		$page = $pages.Add($PageUrl, $layout)
		$page.Update()
		
	    # Update the filename to the one specified in the XML, add HTML content to Page Content zone
	    $item = $page.ListItem
		$item[&quot;Title&quot;] = $PageTitle;
		$item[&quot;Page Content&quot;] = $PageContent;
		$item.Update()
		
	    # Check-in and publish page
	    $item.File.CheckIn(&quot;&quot;)
	    $item.File.Publish(&quot;&quot;)
		$file = $item.File
		$pWeb.Update()
		
		} #end Page Foreach
		
		} # End if block 
		Start-Sleep -Seconds 2
		} #End Site ForEach
		New-BalloonTip -TipText &quot;The specified subsites have been created.&quot; `
		-TipTitle &quot;Sites created successfully&quot;
	#EndRegion Create Subsites
	
	#Region Clean up and launch site
	# Dispose all objects #
	Stop-SPAssignment -Global

	#Region Start SharePoint Warmup
	.\Start-SharePointWarmup.ps1 -WebApp $Url
	#EndRegion
	
	# Set Error and Warning Preferences back #
	$ErrorActionPreference = $ErrorPref
	$WarningPreference = $WarningPref

	# Open the site in IE #
	$ie = New-Object -ComObject InternetExplorer.Application
	$ie.Navigate($Url)
	$ie.Visible = $true;

	Write-Progress -Activity &quot;Launching the site in Internet Explorer&quot; `
	-Status &quot;Opening IExplore.exe&quot;
	#EndRegion Clean up and launch site
} #end Web App ForEach

#Region Calculate running time and finish up
$EndTime = Get-Date
$TimeSpan = New-TimeSpan $StartTime $EndTime
$Mins = $TimeSpan.Minutes
$Secs = $TimeSpan.Seconds
$Time = $EndTime.ToShortTimeString()
# Tell us it's done #
Write-Host &quot;------------------------------------------------------------------&quot;
Write-Host &quot; Portal Configuration Complete at $($Time).&quot;
Write-Host &quot; Process took $($Mins) minutes and $($Secs) seconds to complete.&quot;
Write-Host &quot;------------------------------------------------------------------&quot;
Stop-SPAssignment -Global

New-BalloonTip -TipText &quot;Portal configuration complete at $($Time).&quot; `
-TipTitle &quot;Portal configuration complete!&quot;

#EndRegion Calculate running time and finish up
} #end If DialogResult = OK

#EndRegion Web App ForEach-Object Loop to create everything

#Region Else blocks
# If the Cancel button is clicked, exit #
elseif($objForm.DialogResult -eq &quot;Cancel&quot;){return} #end Else

# If attempting to run without selecting at least one site, output message #
else{Write-Warning &quot;You must select at least one web application!&quot;}
#EndRegion Else blocks

}#endFunction

#EndRegion New-SPWebApplicationFromXml

SharePoint Saturday Cincinnati 2012


This morning I spoke in front of a great crowd at the second annual SharePoint Saturday Cincinnati, also dubbed ScarePoint Saturday Spookinnati!

I chose to re-use my Build your SharePoint Internet presence with PowerShell presentation, as I still think it’s a good presentation that gives a good introductory view into how you can automate site provisioning with PowerShell. I also try to keep it light from a technical standpoint and tend to focus more on the business case around using PowerShell as an automation tool.

Below is a description of the topic itself along with PowerPoint Slides and the PowerShell and XML code that was used in the demo:

Build your SharePoint Internet presence with PowerShell

The topic: Build your SharePoint Internet presence with PowerShell
The story: Everybody knows PowerShell is powerful, it’s in the name! But did you know that PowerShell can read and understand XML? By leveraging XML among other things, complete builds can be automated – making them efficient and predictable.

In this fun, interactive and demo-filled session – I will show you how you can leverage PowerShell to help you build your branded, company website from the ground up using PowerShell and XML. I will also pass along some tips and tricks that will help you become a PowerShell Rockstar!

Here are my slides, and below are the code snippets:

Demo Script – Setup-SPWebAppAndSite.ps1

XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<SubSites>
	<Sites SPSiteUrl="http://www.vandelay.com">
		<!-- root site -->
		<Site Create="false">
			<SiteTitle>Home</SiteTitle>
			<SiteUrl>http://www.vandelay.com/</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Home</PageTitle>
			   <PageUrl>Home.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
			<Page>
			   <PageTitle>Terms of Use</PageTitle>
			   <PageUrl>Terms-of-Use.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
			<Page>
			   <PageTitle>Privacy Policy</PageTitle>
			   <PageUrl>Privacy-Policy.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
			<Page>
			   <PageTitle>Linking Policy</PageTitle>
			   <PageUrl>Linking-Policy.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
			<Page>
			   <PageTitle>Legal Disclaimer</PageTitle>
			   <PageUrl>Legal-Disclaimer.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
			<Page>
			   <PageTitle>404 - Page Not Found</PageTitle>
			   <PageUrl>Page-Not-Found.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
		   </Page>
		</Site>
		<!-- 2nd level sites -->
		<Site>
			<SiteTitle>Products</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Products</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Awesome Widget</PageTitle>
			   <PageUrl>Awesome-Widget.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>The Spectacular Thingamajig</PageTitle>
			   <PageUrl>The-Spectacular-Thingamajig.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Store</PageTitle>
			   <PageUrl>Store.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>Solutions</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Solutions</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Customer Engagement</PageTitle>
			   <PageUrl>Customer-Engagement.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Custom Solutions</PageTitle>
			   <PageUrl>Custom-Solutions.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>Shipping and Returns</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Shipping-and-Returns</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Shipping Policies</PageTitle>
			   <PageUrl>Shipping-Policies.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Return Policies</PageTitle>
			   <PageUrl>Return-Policies.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>About Us</SiteTitle>
			<SiteUrl>http://www.vandelay.com/About-Us</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Company</PageTitle>
			   <PageUrl>Company.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>History</PageTitle>
			   <PageUrl>History.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Locations</PageTitle>
			   <PageUrl>Locations.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Blank Web Part page</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Employment Opportunities</PageTitle>
			   <PageUrl>Employment-Opportunities.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>Contact Us</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Contact-Us</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Social Media</PageTitle>
			   <PageUrl>Social-Media.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Locations</PageTitle>
			   <PageUrl>Locations.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Service Requests</PageTitle>
			   <PageUrl>Service-Requests.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Request a Catalog</PageTitle>
			   <PageUrl>Request-a-Catalog.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>What We Do</SiteTitle>
			<SiteUrl>http://www.vandelay.com/What-We-Do</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Engagement</PageTitle>
			   <PageUrl>Engagement.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Ambassadors</PageTitle>
			   <PageUrl>Ambassadors.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>Our Company</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Our-Company</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
			<Page>
			   <PageTitle>Forms</PageTitle>
			   <PageUrl>Forms.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
			<Page>
			   <PageTitle>Travel</PageTitle>
			   <PageUrl>Travel.aspx</PageUrl>
			   <PageContent></PageContent>
			   <PageLayout>Body Only</PageLayout>
			</Page>
		</Site>
		<Site>
			<SiteTitle>Our Customers</SiteTitle>
			<SiteUrl>http://www.vandelay.com/Our-Customers</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
		</Site>
		<Site>
			<SiteTitle>News</SiteTitle>
			<SiteUrl>http://www.vandelay.com/News</SiteUrl>
			<WebTemplate>CMSPUBLISHING#0</WebTemplate>
			<LangId>1033</LangId>
		</Site>
	</Sites>
</SubSites>

PowerShell code:

#Region New-SPWebApplicationFromXml
function New-SPWebApplicationFromXml {
<#
.Synopsis
	This advanced PowerShell Function uses XML and PowerShell code to provision
	one or more Web Applications, Site Colections, Subsites and Pages. It can
	also deploy and activate solutions and features.
.Description
	This advanced script uses New-SPWebApplication, New-SPSite and
	Enable-SPFeature to configure web applications and site collections using
	specified Site Templates from the included XML. Features, Managed Paths,
	subsites and even Publishing pages can be created using XML as the input.
.Example
	C:\PS>New-SPWebApplicationFromXml -ConfigXmlInput .\WebApps.xml `
	-SubsiteXmlInput .\Subsites.xml

	This example runs with the default parameter values to configure a Web App
	and Site Collection based on the contents of an XML file called
	WebApps.xml in the current file directory.
.Notes
	Name: New-SPWebApplicationFromXml
	Author: Ryan Dennis
	Last Edit: 9/7/2012
	Keywords: New-SPWebApplication, New-SPSite
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$ConfigXmlInput,
[Parameter(Mandatory=$true)][System.String]$SubsiteXmlInput
)

#Region Miscellaneous stuff at the beginning
# If SharePoint Snapin isn't loaded - load it #
if ((Get-PSSnapin Microsoft.SharePoint.PowerShell)-eq $null)
{
	Write-Warning "Adding SharePoint Snapin"
	try	{ Add-PSSnapin Microsoft.SharePoint.PowerShell }
	catch { throw "Unable to add SharePoint Snapin";return }
}
# Start SP Assignment for proper disposal of objects such as SPSite and SPWeb #
Start-SPAssignment -Global

# Read Web Apps from XML file #
[xml]$WebAppXml = Get-Content $($ConfigXmlInput)
if ($WebAppXml -eq $null) { return }

[xml]$SubsiteXml = Get-Content $($SubsiteXmlInput)
if ($SubsiteXml -eq $null) { return }

#EndRegion

#Region Enable Blob Cache function
function Enable-SPBlobCache {
param(
	[Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
	[Microsoft.SharePoint.PowerShell.SPWebApplicationPipeBind]
	$WebApplication,
	[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=1)]
	$BlobCacheLocation="C:\BlobCache\14"
)

process {
    $WebApp = $WebApplication.Read()
    # SPWebConfigModification to enable BlobCache
    $configMod1 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
    $configMod1.Path = "configuration/SharePoint/BlobCache"
    $configMod1.Name = "enabled"
    $configMod1.Sequence = 0
    $configMod1.Owner = "BlobCacheMod"
    ## SPWebConfigModificationType.EnsureChildNode -> 0
    ## SPWebConfigModificationType.EnsureAttribute -> 1
    ## SPWebConfigModificationType.EnsureSection -> 2
    $configMod1.Type = 1
    $configMod1.Value = "true"

    ######################################################################

	# SPWebConfigModification to enable client-side Blob caching (max-age)
    $configMod2 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
    $configMod2.Path = "configuration/SharePoint/BlobCache"
    $configMod2.Name = "max-age"
    $configMod2.Sequence = 0
    $configMod2.Owner = "BlobCacheMod"
    ## SPWebConfigModificationType.EnsureChildNode -> 0
    ## SPWebConfigModificationType.EnsureAttribute -> 1
    ## SPWebConfigModificationType.EnsureSection -> 2
    $configMod2.Type = 1
    $configMod2.Value = "86400"

	######################################################################

	# SPWebConfigModification to change the default location for the Blob Cache files
	$configMod3 = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
	$configMod3.Path = "configuration/SharePoint/BlobCache"
	$configMod3.Name = "location"
	$configMod3.Sequence = "0"
	$configMod3.Owner = "BlobCacheMod"
	## SPWebConfigModificationType.EnsureChildNode -> 0
    ## SPWebConfigModificationType.EnsureAttribute -> 1
    ## SPWebConfigModificationType.EnsureSection -> 2
	$configMod3.Type = 1
	$configMod3.Value = $BlobCacheLocation
    # Add mods, update, and apply
    $WebApp.WebConfigModifications.Add( $configMod1 )
    $WebApp.WebConfigModifications.Add( $configMod2 )
	$WebApp.WebConfigModifications.Add( $configMod3 )
    $WebApp.Update()
    $WebApp.Parent.ApplyWebConfigModifications()
}
}

#EndRegion Blob Cache Function

#Region Load the Form Dialog
# Load Assemblies for System.Windows.Forms and System.Drawing #
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

# Store the 14 Hive in Variable, create an Img variable for Icon #
$14 = 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14'
$Img = $14+"\Template\Images\Favicon.ico"

# Create the Form Object #
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "SharePoint Web Application Deployment Wizard"
$objForm.Size = New-Object System.Drawing.Size(500,350)
$objForm.StartPosition = "CenterScreen"
$objForm.Icon = $Img
$objForm.FormBorderStyle = 'FixedDialog'
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
    {
		$objForm.DialogResult = [System.Windows.Forms.DialogResult]::OK
		$SelectedApps = $null
		[System.String]$Items=$objListBox.SelectedItems;
		[System.Array]$SelectedApps=$Items.Split(' ');
		if($SelectedApps -eq $null){
		throw "You must select at least one web application!"}
		$objForm.Close()
	}
}
)
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape"){$objForm.Close()}})

# OK Button #
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(330,280)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click(
{
	$objForm.DialogResult = [System.Windows.Forms.DialogResult]::OK
	$SelectedApps = $null
	[System.String]$Items=$objListBox.SelectedItems;
	[System.Array]$SelectedApps=$Items.Split(' ');
	if($SelectedApps -eq $null)
	{
	throw "You must select at least one web application!"
	}
	$objForm.Close()
})

# Cancel Button #
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(405,280)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click(
{
	$objForm.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
	$objForm.Close()
}
)

# Listbox Object #
$objListBox = New-Object System.Windows.Forms.ListBox
$objListBox.Location = New-Object System.Drawing.Size(10,40)
$objListBox.Size = New-Object System.Drawing.Size(470,20)
$objListBox.Height = 230
$objListBox.SelectionMode = "MultiExtended"

# Listbox Label #
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(470,20)
$objLabel.Text = "Please select the web application(s) you wish to deploy:"

$WebApps = $WebAppXml.WebApplications.WebApplication
$WebApps | ForEach-Object {
	[void] $objListBox.Items.Add($_.WebAppConfig.HostHeader)
}

# Add the controls to the Form Object #
$objForm.Controls.Add($objLabel)
$objForm.Controls.add($objListBox)
$objForm.Controls.Add($OKButton)
$objForm.Controls.Add($CancelButton)
$objForm.Controls.Add($SearchButton)

# Display the form on top of all other windows #
$objForm.Topmost = $True

# Add the dialog box to the screen #
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()

#EndRegion Form Dialog

#Region Web App ForEach-Object Loop to create everything
# If the dialog result is OK, run the code to create navigation #
if ($objForm.DialogResult -eq "OK" -and $SelectedApps -ne $null)
{
$SelectedApps | ForEach-Object {

	#Region Create Web Application
	# Clear Host for a clean, empty shell #
	Clear-Host

	[System.String]$CurrentWA = $_
	$wa = $WebAppXml.WebApplications.WebApplication |
	Where-Object {$_.WebAppConfig.HostHeader -eq $CurrentWA}

	# Store start time in variable for calculation later #
	$StartTime = Get-Date

	# Read in list of sites from XML file and create variables for use later #
	$Name = $wa.WebAppConfig.Name
	$ApplicationPool = $wa.WebAppConfig.AppPool
	$ApplicationPoolAccount = $wa.WebAppConfig.AppPoolAccount
	$DatabaseServer = $wa.WebAppConfig.DBServer
	$DatabaseName = $wa.WebAppConfig.DBName
	$InetpubPath = $wa.WebAppConfig.InetpubPath
	$HostHeader = $wa.WebAppConfig.HostHeader
	$Port = $wa.WebAppConfig.Port
	$WebsitePath=$InetpubPath+"\"+$HostHeader+$Port
	$Protocol = $wa.WebAppConfig.Protocol
	$Url = $Protocol+"://"+$HostHeader+":"+$Port
	$ManagedPaths = $wa.WebAppConfig.ManagedPaths
	$Solutions = $wa.WebAppConfig.Solutions
	$BlobCacheLocation = $wa.WebAppConfig.BlobCacheLocation
	$AuthType = $wa.WebAppConfig.Authentication.Type
	$AuthMethod = $wa.WebAppConfig.Authentication.AuthMethod
	$AuthProviderName = $wa.WebAppConfig.Authentication.AuthProvider.Name
	$AuthProviderMember = $wa.WebAppConfig.Authentication.AuthProvider.MembershipProviderName
	$AuthProviderRole = $wa.WebAppConfig.Authentication.AuthProvider.RoleProviderName

	# Start SP Assignment for object disposal later #
	Start-SPAssignment -Global

	# Change Shell Title #
	$title = $Host.UI.RawUI.WindowTitle
	$Host.UI.RawUI.WindowTitle = "Provisioning Web Application..."

	$ErrorPref = $ErrorActionPreference
	$ErrorActionPreference = "SilentlyContinue"
	$WarningPref = $WarningPreference
	$WarningPreference = "SilentlyContinue"

	# Tell us the Web App is getting created #
	$iMax = 11 #Number of Steps#
	$i = 0 #Number to start on#

	$i++ #step 1
	Write-Progress -Activity "Step $i of $iMax : Creating Web Application at Url $($HostHeader)" `
	-PercentComplete ($i/$imax*100) -Status "Creating IIS Website, Content Database and Application Pool"
	# Create a Classic App #
	if($AuthType -eq "Classic"){
		try {
			# Create the Web App #
			New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `
			-ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `
			-DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `
			-Path $WebsitePath -Url $HostHeader -WarningAction SilentlyContinue | Out-Null
		}
		catch {	throw "Unable to create the web application";return	}
	}
	# Create a Windows Claims App #
	if($AuthType -eq "Claims"){
		try {
			# Create the auth provider #
			$ap = New-SPAuthenticationProvider
			# Create the Web App #
			New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `
			-ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `
			-DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `
			-Path $WebsitePath -Url $HostHeader -WarningAction SilentlyContinue `
			-AuthenticationProvider $ap -AuthenticationMethod $AuthMethod | Out-Null
		}
		catch {	throw "Unable to create the web application";return	}
	}
	#EndRegion Create Web Application

	#Region Creating Managed Paths
	$i++ #Step2
	# Create Managed Paths #
	$wa.WebAppConfig.ManagedPaths.ManagedPath | ForEach-Object {
		$path = $_.path
		$type = $_.type
		if($type -eq "explicit"){
			New-SPManagedPath -Explicit -RelativeURL $path -WebApplication $Url `
			-ErrorAction SilentlyContinue | Out-Null
		}
		elseif($type -eq "wildcard"){
			New-SPManagedPath -RelativeURL $path -WebApplication $Url `
			-ErrorAction SilentlyContinue | Out-Null
		}
	}
	#EndRegion Creating Managed Paths

	#Region Installing Solutions
	$i++ #Step3
	# Change Shell Title #
	$Host.UI.RawUI.WindowTitle = "Installing Solutions..."
	# Enable solutions #
	try {
		$Solutions.Solution | ForEach-Object {
		$SolutionId = $_
			if($SolutionId.GACDeployment -eq "true"){
			Write-Progress -Activity "Step $i of $iMax : Installing Solutions..." `
			-PercentComplete ($i/$imax*100) -Status "Activating $($SolutionId) solution"
			Install-SPSolution $($SolutionId) -WebApplication $Url `
			-GACDeployment -ErrorVariable +err -Confirm:$false
			Start-Sleep -Seconds 5
			}
			else{
			Write-Progress -Activity "Step $i of $iMax : Installing Solutions..." `
			-PercentComplete ($i/$imax*100) -Status "Activating $($SolutionId) solution"
			Install-SPSolution $($SolutionId) -WebApplication $Url `
			-ErrorVariable +err -Confirm:$false
			Start-Sleep -Seconds 5
			}
		}
	}
	catch { Write-Error "Error enabling solution $($SolutionId)" }
	#EndRegion Installing Solutions

	#Region Create Site Collections
	# Change Shell Title #
	$Host.UI.RawUI.WindowTitle = "Provisioning Site Collections..."
	$i++ #step4
	$siteCollections = $wa.SiteCollections
	# Create Site Collections using ForEach-Object loop #
	try {
	$SiteCollections.SiteCollection | ForEach-Object {
		$NewSiteUrl = $Url+$_.Path
		$sName = $_.Name
		$sOAlias = $_.OwnerAlias
		$sOEmail = $_.OwnerEmail
		$sSOAlias = $_.SecondaryOwnerAlias
		$sSOEmail = $_.SecondaryOwnerEmail
		$sTemplate = $_.WebTemplate
		$subSites = $_.Sites
		$srchUrl = $_.SearchSettings.SearchCenterUrl
		$srchDD = $_.SearchSettings.DropDownMode
		$srchPage = $_.SearchSettings.TargetResultsPage
		# Tell us the Site Collection is getting created #
		Write-Progress -Activity "Step $i of $iMax : Creating Site Collection at Url $($HostHeader)..." `
		-PercentComplete ($i/$imax*100) -Status "Provisioning $($sTemplate) site"
		$SPSite = New-SPSite -Name $sName -OwnerAlias $sOAlias -OwnerEmail $sOEmail `
		-SecondaryOwnerAlias $sSOAlias -SecondaryEmail $sSOEmail `
		-Template $sTemplate -Url $NewSiteUrl | Out-Null
		Start-Sleep -Seconds 5

		$_.Features.Feature | ForEach-Object {
		# Enable Features #
		try {
			$FeatureId = $_
			Write-Progress -Activity "Step $i of $iMax : Configuring Site Features..." `
			-PercentComplete ($i/$imax*100) -Status "Activating $($FeatureId) feature"
			Enable-SPFeature -Identity $($FeatureId) -Url $NewSiteUrl -ErrorVariable +err `
			-ErrorAction SilentlyContinue -Confirm:$false
			}
		catch { Write-Error "Error activating feature $err" }
		} #end Feature ForEach

		Start-Sleep -Seconds 5

		#Region Search Settings
		.\Set-SPSiteSearchSettings.ps1 -SiteUrl $NewSiteUrl -SearchCenterUrl $srchUrl `
		-SearchDropDownMode $srchDD -SearchResultsUrl $srchPage
		#EndRegion Search Settings

	} #End Site Collection ForEach
	} #End Site Collection Try
	catch { throw "Unable to create site collection at path: $NewSiteUrl";return }

	#EndRegion Create Site Collections

	#Region Configure Blob Caching
	$i++ #step 7
	Write-Progress -Activity "Step $i of $iMax : Configuring Cache Settings..." `
	-PercentComplete ($i/$imax*100) -Status "Configuring BLOB Caching"
	try {
	Enable-SPBlobCache -WebApplication $Url -BlobCacheLocation $BlobCacheLocation
	}
	catch { Write-Error "Unable to configure BLOB caching" }
	#EndRegion Configure Blob Caching

	#Region Run External Scripts
		$location = Get-Location
		$modPath = $PSHOME+"\Modules\PSSAT002\"
		Set-Location $modPath

		#Region Create Web App Policy
		$i++ #step8
		Write-Progress -Activity "Step $i of $iMax : Creating Web Application Policy..." `
		-PercentComplete ($i/$imax*100) -Status "Configuring Full Control Policy"

		.\Configure-SPWebApplicationUserPolicy.ps1 -WebApplicationUrl $Url
		#EndRegion Create Web App Policy

		#Region Meta Fields
		# Create Meta Fields #
		$i++ #step 9
		Write-Progress -Activity "Step $i of $iMax : Configuring SEO Fields..." `
		-PercentComplete ($i/$imax*100) -Status "Provisioning SEO Meta Fields"

		#Write-Host "Configuring SEO fields"
		.\Create-MaventionMetaFields.ps1 -Url $Url
		#EndRegion MetaFields

		Set-Location $location
	#EndRegion Run External Scripts

	#Region Create Subsites

		# Create subwebs from XML input #
		$i++ #step 11
		Write-Progress -Activity "Step $i of $iMax : Creating Subsites from XML..." `
		-PercentComplete ($i/$imax*100) -Status "Retrieving sites from XML file"
		Start-SPAssignment -Global

		$SubsiteXml.SubSites.Sites.Site | ForEach-Object {
		Write-Progress -Activity "Step $i of $iMax : Creating Subsites from XML..." `
		-PercentComplete ($i/$imax*100) -Status "Creating an SPWeb at $($SiteUrl)"
		$SPSiteUrl = $_.SPSiteUrl
		$SiteTitle = [string]$_.SiteTitle
		$SiteUrl = [string]$_.SiteUrl
		$SiteOwner = [string]$_.Owner
		$SiteUser = [string]$_.User
		$WebTemplate = [string]$_.WebTemplate
		$LangId = [string]$_.LangId
		$SiteUrl = $SiteUrl
		# Create the SPWeb #
		if ($_.create -ne "false")
		{
		$Web = New-SPWeb -Url $SiteUrl -Language $LangId -Template $WebTemplate `
		-Name $SiteTitle -ErrorAction Inquire
		}
		else {
		$Web = Get-SPWeb -Identity $SiteUrl -ErrorAction Inquire
		}
		# Get publishing site and web objects
		$site = $Web.Site
		$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)

		# Create all Pages using ForEach-Object #
		if ($_.Page -ne $null){
		$_.Page | ForEach-Object {

		# Create page content variables from XML file
		$PageTitle = [string]$_.PageTitle
		$PageUrl = [string]$_.PageUrl
		$PageLayout = [string]$_.PageLayout
		#$PageContent = [xml]$_.PageContent
		$PageImage = [string]$_.PageImage
		$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}

	    # Create blank page using Add method
		Write-Progress -Activity "Step $i of $iMax : Creating Subsites from XML..." `
		-PercentComplete ($i/$imax*100) -Status "Creating $($PageTitle).aspx page in $($SiteTitle) site..."
	    $pages = $pWeb.GetPublishingPages($pWeb)
		$page = $pages.Add($PageUrl, $layout)
		$page.Update()

	    # Update the filename to the one specified in the XML, add HTML content to Page Content zone
	    $item = $page.ListItem
		$item["Title"] = $PageTitle;
		$item["Page Content"] = $PageContent;
		$item.Update()

	    # Check-in and publish page
	    $item.File.CheckIn("")
	    $item.File.Publish("")
		$file = $item.File
		$pWeb.Update()

		} #end Page Foreach

		} # End if block
		Start-Sleep -Seconds 2
		} #End Site ForEach

	#EndRegion Create Subsites

	#Region Clean up and launch site
	# Dispose all objects #
	Stop-SPAssignment -Global

	#Region Start SharePoint Warmup
	.\Start-SharePointWarmup.ps1 -WebApp $Url
	#EndRegion

	# Set Error and Warning Preferences back #
	$ErrorActionPreference = $ErrorPref
	$WarningPreference = $WarningPref

	# Open the site in IE #
	$ie = New-Object -ComObject InternetExplorer.Application
	$ie.Navigate($Url)
	$ie.Visible = $true;

	Write-Progress -Activity "Launching the site in Internet Explorer" `
	-Status "Opening IExplore.exe"
	#EndRegion Clean up and launch site
} #end Web App ForEach

#Region Calculate running time and finish up
$EndTime = Get-Date
$TimeSpan = New-TimeSpan $StartTime $EndTime
$Mins = $TimeSpan.Minutes
$Secs = $TimeSpan.Seconds
$Time = $EndTime.ToShortTimeString()
# Tell us it's done #
Write-Host "------------------------------------------------------------------"
Write-Host " Portal Configuration Complete at $($Time)."
Write-Host " Process took $($Mins) minutes and $($Secs) seconds to complete."
Write-Host "------------------------------------------------------------------"
Stop-SPAssignment -Global
#EndRegion Calculate running time and finish up
} #end If DialogResult = OK

#EndRegion Web App ForEach-Object Loop to create everything

#Region Else blocks
# If the Cancel button is clicked, exit #
elseif($objForm.DialogResult -eq "Cancel"){return} #end Else

# If attempting to run without selecting at least one site, output message #
else{Write-Warning "You must select at least one web application!"}
#EndRegion Else blocks

}#endFunction

#EndRegion New-SPWebApplicationFromXml

PowerShell Saturday Charlotte 2012


Today I had the privilege of speaking (twice) at the second PowerShell Saturday, in Charlotte, NC!

Originally I was accepted to speak about advanced functions and XML, so I tweaked my “Build your SharePoint Internet presence with PowerShell” talk to be more of a deep-dive into XML and PowerShell advanced functions (it’s also called “The Power is in the Shell, Use it Wisely!”). However, another speaker was unable to attend and I ended up doing two SharePoint-focused PowerShell presentations. I’ll detail them below, and since this will be a long post, here are links to the different areas within the page:

  1. The Power is in the Shell, Use it Wisely!
  2. Getting Started with SharePoint + PowerShell

The Power is in the Shell, Use it Wisely!

The topic: The Power is in the Shell, Use it Wisely!
The story: Everybody knows PowerShell is powerful, it’s in the name! But did you know that PowerShell can read and understand XML? By leveraging XML among other things, complete builds can be automated – making them efficient and predictable.

In this fun, interactive and demo-filled session – I will show you how you can leverage PowerShell to help you build your branded, company website from the ground up using PowerShell and XML. I will also pass along some tips and tricks that will help you become a PowerShell Rockstar!

This was the second PowerShell Saturday, and the first in Charlotte – and I was very proud to be a part of a great event.

My session went pretty flawlessly, as I lucked out and had zero issues with the presentation or the demos. For those of you who attended, thank you for being a part of it – and if you have any feedback or questions feel free to contact me either on Twitter or via e-mail (Ryan at SharePointRyan dot com).

I promised to upload my slides and demo PowerShell code, so the slides are on Slideshare and the XML and PowerShell code is saved on SkyDrive.

Intro to SharePoint + PowerShell

The topic:  Intro to SharePoint + PowerShell
The story: You may have heard of PowerShell, but do you know what it’s capable of? Gone are the days of long, painful STSADM batch files – we have Windows PowerShell, and it’s here to stay.Learn how you can use Windows PowerShell both to perform simple one-off tasks as well as complex, bulk operations. Leveraging the Object Model gives Administrators and Developers the ability to do in a few lines of code what would’ve taken a lot more work (and probably a Developer or two) in the WSS platform. You’ll see how you can get started with PowerShell, and you will hopefully leave with not only a greater understanding of what PowerShell is – but what it is capable of and how you can start using it to automate tasks in your SharePoint 2010 environment.

View all of the presentations from Ryan Dennis.