SharePoint Saturday Dayton 2012


This past weekend I spoke in front of a good sized crowd at the first annual SharePoint Saturday Dayton!

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!

This was the first SharePoint Saturday in Dayton, 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 displayed at the bottom of the post) and the XML and PowerShell code is below:

Demo Script – Setup-SPWebAppAndSite.ps1

XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<Sites>
	<WebAppConfig>
		<Name>Vandelay Industries</Name>
		<AppPool>SharePoint - VandelayDemo</AppPool>
		<AppPoolAccount>ISG1085\SpAppPool</AppPoolAccount>
		<DBServer>ISG1085\SharePoint</DBServer>
		<DBName>SP2010_Content_Vandelay_Demo</DBName>
		<HostHeader>www.vandelay.com</HostHeader>
		<InetpubPath>C:\inetpub\wwwroot\wss\VirtualDirectories</InetpubPath>
		<Port>80</Port>
		<Protocol>http://</Protocol>
		<OwnerAlias>ISG1085\SharePointRyan</OwnerAlias>
		<OwnerEmail>SharePointRyan@demowebsite.com</OwnerEmail>
		<SecondaryOwnerAlias>ISG1085\SPFarm</SecondaryOwnerAlias>
		<SecondaryOwnerEmail>SPFarm@demowebsite.com</SecondaryOwnerEmail>
		<RootSite>
			<WebTemplate>BLANKINTERNET#0</WebTemplate>
		</RootSite>
	</WebAppConfig>
	<!-- root site -->
	<Site Create="false">
		<SiteTitle>Home</SiteTitle>
		<SiteUrl>/</SiteUrl>
		<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>/Products</SiteUrl>
		<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>/Solutions</SiteUrl>
		<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>/Shipping-and-Returns</SiteUrl>
		<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>/About-Us</SiteUrl>
		<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>/Contact-Us</SiteUrl>
		<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>/What-We-Do</SiteUrl>
		<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>/Our-Company</SiteUrl>
		<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>/Our-Customers</SiteUrl>
	</Site>
	<Site>
		<SiteTitle>News</SiteTitle>
		<SiteUrl>/News</SiteUrl>
	</Site>
</Sites>

PowerShell code:

<#
.Synopsis
	This PowerShell Script will create a new Web Application and root Site 
	Collection.
.Description
	This advanced script uses New-SPWebApplication, New-SPSite and 
	Enable-SPFeature to configure a web application and site collection using
	the Publishing Portal Site Template. Once the SPSite is created, 
	Standard and Enterprise Site and Web Features are activated.
.Example
	C:\PS>.\Setup-SPWebAppAndSite.ps1 -XmlInput .\SiteGenerationXml.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 
	SiteGenerationXml.xml in the current file directory.
.Notes
	Name: Setup-SPWebAppAndSite.ps1
	Author: Ryan Dennis
	Last Edit: 6/27/2012
	Keywords: New-SPWebApplication, New-SPSite
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
#Requires -Version 2.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][string]$XmlInput,
[Parameter(Mandatory=$true)][string]$BlobCacheLocation
)
# Store start time in variable for calculation later #
$StartTime = Get-Date

# Clear Host for a clean, empty shell #
Clear-Host

# Read in list of sites from XML file and create variables for use later #
[xml]$SitesXml = Get-Content $($XmlInput)
if ($SitesXml -eq $null) { return }
$Name = $SitesXml.Sites.WebAppConfig.Name
$ApplicationPool = $SitesXml.Sites.WebAppConfig.AppPool
$ApplicationPoolAccount = $SitesXml.Sites.WebAppConfig.AppPoolAccount
$DatabaseServer = $SitesXml.Sites.WebAppConfig.DBServer
$DatabaseName = $SitesXml.Sites.WebAppConfig.DBName
$InetpubPath = $SitesXml.Sites.WebAppConfig.InetpubPath
$HostHeader = $SitesXml.Sites.WebAppConfig.HostHeader
$Port = $SitesXml.Sites.WebAppConfig.Port
$WebsitePath=$InetpubPath+"\"+$HostHeader+$Port
$Protocol = $SitesXml.Sites.WebAppConfig.Protocol
$Url = $Protocol+$HostHeader+":"+$Port
$OwnerAlias = $SitesXml.Sites.WebAppConfig.OwnerAlias
$OwnerEmail = $SitesXml.Sites.WebAppConfig.OwnerEmail
$SecondaryOwnerAlias = $SitesXml.Sites.WebAppConfig.SecondaryOwnerAlias
$SecondaryOwnerEmail = $SitesXml.Sites.WebAppConfig.SecondaryOwnerEmail
$WebTemplate = $SitesXml.Sites.WebAppConfig.RootSite.WebTemplate

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

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

# 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
}
$ErrorPref = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"
$WarningPref = $WarningPreference
$WarningPreference = "SilentlyContinue"

# Tell us the Web App is getting created #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 1 of 10: Creating Web Application at Url $($Url)..."
Write-Host "------------------------------------------------------------------"

# Create the Web App #
New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `
-ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `
-DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `
-Path $WebsitePath -Url $HostHeader | Out-Null

# Add the BUILTIN\Administrators group to Full Control Policy #
$userOrGroup = "BUILTIN\Administrators" 
$displayName = "Administrators" 

$WebApp = Get-SPWebApplication $Name 
$policy = $webApp.Policies.Add($userOrGroup, $displayName) 
$policyRole = $webApp.PolicyRoles.GetSpecialRole([Microsoft.SharePoint.Administration.SPPolicyRoleType]::FullControl) 
$policy.PolicyRoleBindings.Add($policyRole) 
$webApp.Update() 

# Change Shell Title #
$Host.UI.RawUI.WindowTitle = "Provisioning Root Site Collection..."

# Tell us the Site Collection is getting created #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 2 of 10: Creating Root Site Collection..."
Write-Host "------------------------------------------------------------------"

# Create the Root Site #
$SPSite = New-SPSite -Name $Name -OwnerAlias $OwnerAlias -OwnerEmail $OwnerEmail `
-SecondaryOwnerAlias $SecondaryOwnerAlias -SecondaryEmail $SecondaryOwnerEmail `
-Template $WebTemplate -Url $Url | Out-Null

# Tell us the Site Collection is getting created #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 3 of 10: Configuring Cache Settings..."
Write-Host "------------------------------------------------------------------"
Write-Host "Configuring BLOB Caching..."
# Enable SP Blob Cache #
$WebApp = Get-SPWebApplication $Url 
# 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() 

# Sleep for 5 seconds # 
Start-Sleep -Seconds 5

# Enable Output Cache for Root Site Collection # 
Write-Host "Configuring Output Caching..."
$SPSite = Get-SPSite $Url
$cache = New-Object Microsoft.SharePoint.Publishing.SiteCacheSettingsWriter $SPSite
$cache.EnableCache = $true
$cache.AllowPublishingWebPageOverrides = $true
$cache.EnableDebuggingOutput = $true
$cache.SetAnonymousPageCacheProfileId($SPSite, 1)
$cache.SetAuthenticatedPageCacheProfileId($SPSite, 4)
$cache.SetFarmCacheFlushFlag()
$cache.Update()
$SPSite.Dispose()

# Change Shell Title #
$Host.UI.RawUI.WindowTitle = "Activating Features..."

# Activate Standard and Enterprise Features #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 4 of 10: Activating Features..."
Write-Host "------------------------------------------------------------------"
# Standard #
Write-Host "Enabling Standard Site and Web Features..."
Enable-SPFeature BaseSite -Url $Url
Enable-SPFeature BaseWeb -Url $Url
# Enterprise #
Write-Host "Enabling Enterprise Site and Web Features..."
Enable-SPFeature PremiumSite -Url $Url
Enable-SPFeature PremiumWeb -Url $Url
# Team Collaboration Lists #
Enable-SPFeature TeamCollab -Url $Url
# Mavention Meta Fields #
Write-Host "Enabling Mavention Meta Fields Feature..."
Install-SPSolution Mavention.SharePoint.MetaFields.wsp -WebApplication $Url -GACDeployment
Start-Sleep -Seconds 5
Enable-SPFeature -Identity a6ad433b-0bdf-40aa-aec8-6a091d7a3c26 -Url $Url

# Change Shell Title #
$Host.UI.RawUI.WindowTitle = "Configuring Search Center and Settings..."

# Remove OOTB Search Center Lite Web #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 5 of 10: Removing Search Center Subsite..."
Write-Host "------------------------------------------------------------------"
Remove-SPWeb -Identity $Url"/search" -Confirm:$false -ErrorAction SilentlyContinue

# Create Enterprise Search Center Site Collection #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 6 of 10: Creating Enterprise Search Center Site Collection..."
Write-Host "------------------------------------------------------------------"
$searchUrl = $Url+"/search"
New-SPManagedPath -Explicit -RelativeURL search -WebApplication $Url | Out-Null
New-SPSite -Name "Search Center" -OwnerAlias $OwnerAlias `
-OwnerEmail $OwnerEmail -SecondaryOwnerAlias $SecondaryOwnerAlias `
-SecondaryEmail $SecondaryOwnerEmail -Template "SRCHCEN#0" `
-Url $searchUrl | Out-Null
# Apply MaxSiteCount to content DB #
Set-SPContentDatabase -Identity $DatabaseName -MaxSiteCount 2 `
-WarningSiteCount 1 | Out-Null
Set-SPUser -Identity "NT Authority\Authenticated Users" -Web $searchUrl `
-Group "Search Center Visitors"

# Set Site Collection Search Center Settings #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 7 of 10: Configuring Search Scope Settings..."
Write-Host "------------------------------------------------------------------"
<# These are the possible values for Dropdown
Do Not Show Scopes Dropdown, and default to contextual scope	HideScopeDD_DefaultContextual
Do Not Show Scopes Dropdown, and default to target results page	HideScopeDD
Show scopes Dropdown	ShowDD
Show, and default to ‘s’ URL parameter	ShowDD_DefaultURL
Show and default to contextual scope	ShowDD_DefaultContextual
Show, do not include contextual scopes	ShowDD_NoContextual
Show, do not include contextual scopes, and default to ‘s’ URL parameter	ShowDD_NoContextual_DefaultURL
#>

$SPWeb = Get-SPWeb $Url
$SPWeb.AllProperties["SRCH_ENH_FTR_URL"] = "/search/pages"
$SPWeb.AllProperties["SRCH_SITE_DROPDOWN_MODE"] = "ShowDD"
$SPWeb.AllProperties["SRCH_TRAGET_RESULTS_PAGE"] = "/search/pages/results.aspx"
$SPWeb.Update()
# Search Site #
$searchWeb = Get-SPWeb $searchUrl
$searchWeb.AllProperties["SRCH_ENH_FTR_URL"] = "/search/pages"
$searchWeb.AllProperties["SRCH_SITE_DROPDOWN_MODE"] = "ShowDD"
$searchWeb.AllProperties["SRCH_TRAGET_RESULTS_PAGE"] = "/search/pages/results.aspx"
$searchWeb.Update()

# Create Meta Fields #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 8 of 10: Creating SEO Meta Fields..."
Write-Host "------------------------------------------------------------------"
#Assign fieldXML variable with XML string for site column
# Author
$AuthorFieldXML = '<Field Type="Text"
Name="MetaAuthor"
Description="Author Meta Tag"
DisplayName="Author"
StaticName="MetaAuthor"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Copyright
$CopyrightFieldXML = '<Field Type="Text"
Name="MetaCopyright"
Description="Copyright Meta Tag"
DisplayName="Copyright"
StaticName="MetaCopyright"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Description
$DescriptionFieldXML = '<Field Type="Text"
Name="MetaDescription"
Description="Description Meta Tag"
DisplayName="Description"
StaticName="MetaDescription"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Expiration
$ExpirationFieldXML = '<Field Type="Text"
Name="MetaExpiration"
Description="Expiration Meta Tag"
DisplayName="Expiration"
StaticName="MetaExpiration"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Keywords
$KeywordsFieldXML = '<Field Type="Text"
Name="MetaKeywords"
Description="Keywords Meta Tag"
DisplayName="Keywords"
StaticName="MetaKeywords"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Refresh
$RefreshFieldXML = '<Field Type="Text"
Name="MetaRefresh"
Description="Refresh Meta Tag"
DisplayName="Refresh"
StaticName="MetaRefresh"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Robots
$RobotsFieldXML = '<Field Type="Text"
Name="MetaRobots"
Description="Robots Meta Tag"
DisplayName="Robots"
StaticName="MetaRobots"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'
# Title
$TitleFieldXML = '<Field Type="Text"
Name="MetaTitle"
Description="Title Meta Tag"
DisplayName="Title"
StaticName="MetaTitle"
Group="Publishing Meta Tags"
Hidden="FALSE"
Required="FALSE"
Sealed="FALSE"
ShowInDisplayForm="TRUE"
ShowInEditForm="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"></Field>'

	$SPWeb = Get-SPWeb $Url
	$SPWeb.Fields.AddFieldAsXml($AuthorFieldXML)
	$SPWeb.Fields.AddFieldAsXml($CopyrightFieldXML)
	$SPWeb.Fields.AddFieldAsXml($DescriptionFieldXML)
	$SPWeb.Fields.AddFieldAsXml($ExpirationFieldXML)
	$SPWeb.Fields.AddFieldAsXml($KeywordsFieldXML)
	$SPWeb.Fields.AddFieldAsXml($RefreshFieldXML)
	$SPWeb.Fields.AddFieldAsXml($RobotsFieldXML)
	$SPWeb.Fields.AddFieldAsXml($TitleFieldXML)
	# Grab columns for manipulation
	$Author = $SPWeb.Fields["MetaAuthor"]
	$Copyright = $SPWeb.Fields["MetaCopyright"]
	$Description = $SPWeb.Fields["MetaDescription"]
	$Expiration = $SPWeb.Fields["MetaExpiration"]
	$Keywords = $SPWeb.Fields["MetaKeywords"]
	$Refresh = $SPWeb.Fields["MetaRefresh"]
	$Robots = $SPWeb.Fields["MetaRobots"]
	$Title = $SPWeb.Fields["MetaTitle"]
	# Rename Display Name
	$Author.Title = "Author"
	$Copyright.Title = "Copyright"
	$Description.Title = "Description"
	$Expiration.Title = "Expiration"
	$Keywords.Title = "Keywords"
	$Refresh.Title = "Refresh"
	$Robots.Title = "Robots"
	$Title.Title = "Title"
	# Update All
	$Author.Update()
	$Copyright.Update()
	$Description.Update()
	$Expiration.Update()
	$Keywords.Update()
	$Refresh.Update()
	$Robots.Update()
	$Title.Update()
	$SPWeb.Dispose()

# Add the columns to the Welcome Page content type #
$Web = Get-SPWeb $Url
$Ctype = $Web.ContentTypes["Welcome Page"]
$fields = $web.Fields | Where-Object {$_.group -eq "Publishing Meta Tags"}
$fields | ForEach-Object {
$Ctype.FieldLinks.Add($_)
$Ctype.Update($true)
$Web.Update()
}
$Web.Dispose()

# Change Shell Title #
$Host.UI.RawUI.WindowTitle = "Creating Subsites from XML..."

# Create subwebs from XML input #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 9 of 10: Creating subsites from XML file..."
Write-Host "------------------------------------------------------------------"

Start-SPAssignment -Global

# Loop through each site node to extract data #
$SitesXml.Sites.Site | ForEach-Object {
	Write-Host "---------------------------------------------------------------"
	Write-Host " Step 9 of 10: Creating an SPWeb at $($SiteUrl)"
	Write-Host "---------------------------------------------------------------"
	$SiteTitle = [string]$_.SiteTitle
	$SiteUrl = [string]$_.SiteUrl
	$SiteOwner = [string]$_.Owner
	$SiteUser = [String]$_.User
	$WebTemplate = "CMSPUBLISHING#0"
	$LangId = "1033"
	$SiteUrl = $Url+$SiteUrl
	# Create the SPWeb #
	if ($_.create -ne "false")
	{
	$Web = New-SPWeb -Url $SiteUrl -Language $LangId -Template $WebTemplate `
	-Name $SiteTitle
	}
	# Get publishing site and web objects
	$site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
	$psite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($site)
	$web = $site.OpenWeb()
	$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)

	# 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 = [xml]$_.PageContent
	$PageImage = [string]$_.PageImage
	$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
	
    # Create blank page using Add method
	Write-Host "Creating $($PageTitle).aspx page"
    $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;
	
	# Experimenting with adding a CEWP #
#	$page.CheckOut() 
#	$webpartmanager = $web.GetLimitedWebPartManager($page.Url,
#	[System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared) 
#	$webpart = New-Object  Microsoft.SharePoint.WebPartPages.ContentEditorWebPart
#	$webpart.ChromeType = [System.Web.UI.WebControls.WebParts.PartChromeType]::None;
#	$webpart.Title = "Added By PowerShell" 
#	$webpart.Content = $PageContent
#	$webpartmanager.AddWebPart($webpart, "Header", 0); 
	$item.Update()
	
    # Check-in and publish page
    $item.File.CheckIn("")
    $item.File.Publish("")
	$file = $item.File
	$pWeb.Update()
	
	} #end Page Foreach
	
	} # End if block #
	
} # End ForEach-Object loop #

# Upload Footer List and create list #
Write-Host "------------------------------------------------------------------"
Write-Host " Step 10 of 10: Creating Footer List and applying branding..."
Write-Host "------------------------------------------------------------------"
$site = Get-SPSite $Url
$Web = $site.OpenWeb()
$spFolder = $web.GetFolder("List Template Gallery")
$spFileCollection = $spFolder.Files
$file = Get-Item C:\Solutions\ConsumersEnergy\CEEP-FooterDirectoryList-LT.stp
$spFileCollection.Add("_catalogs/lt/CEEP-FooterDirectoryList-LT.stp", $file.OpenRead(), $true) | Out-Null
$listTemplates = $site.GetCustomListTemplates($web)
$Web.Lists.Add("CEEP-FooterDirectoryList","",$listTemplates["CEEP-FooterDirectoryList-LT"]) | Out-Null
$Web.Dispose()
$site.Dispose()
Enable-SPFeature -Identity "8d36bad6-e39a-41be-aff4-1a4be71ddcb6" -Url $Url | Out-Null




$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 "------------------------------------------------------------------"

# Set the Window Title back to default #
$Host.UI.RawUI.WindowTitle = $title

# Hit the site to warm it up #
function get-webpage([string]$url,[System.Net.NetworkCredential]$cred=$null)
{
   $wc = new-object net.webclient
   if($cred -eq $null)
   {
     $cred = [System.Net.CredentialCache]::DefaultCredentials;
   }
   $wc.credentials = $cred;
   return $wc.DownloadString($url);
}

Write-Host "------------------------------------------------------------------"
Write-Host " Warming up the new Sites"
Write-Host "------------------------------------------------------------------" 
$cred = [System.Net.CredentialCache]::DefaultCredentials;
$sites = Get-SPSite -WebApplication $WebApp -Limit ALL
foreach ($site in $sites) {
$siteurl = $site.url
$spsite = New-Object Microsoft.SharePoint.SPSite($siteurl)
$pubsite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($spsite)
foreach ($web in $site.AllWebs) {
$pubweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$pages = $pubweb.GetPublishingPages($pubweb)
	foreach ($page in $pages) {
	$html = Get-WebPage -Url $page.uri -cred $cred;
	#Write-Host $page.uri
	}
}
}

# Dispose all objects #
Stop-SPAssignment -Global

# 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;
Advertisements

SharePoint Saturday Cincinnati 2011


This past weekend I broke new ground in my career – I completed my first public speaking engagement! While I have spoken on various topics in front of my SharePoint Team at ICC – this was my first public speaking engagement and overall I think it went very well.

The topic: The Power is in the Shell, use it wisely!
The story: What is PowerShell – how does it fit into the SharePoint 2010 puzzle? How can we take commands run in the Shell and easily convert them to scripts or functions? How can we use the Get-Content cmdlet and some XML to automate content loading or migrations? What are some best practices around PowerShell as it relates to SharePoint 2010?

This was the first SharePoint Saturday in Cincinnati, 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 three demos. I had a small group of attendees, but all of them were very engaged in dialog throughout. 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 (rdennis at iccohio 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 below:

First demo function – Set-SPWebTitle

function Set-SPWebTitle {
Param(
[string]$SiteUrl,
[string]$SiteTitle
)
$site = Get-SPSite $SiteUrl
$web = $site.RootWeb                                                                                                   
$web.Title = $SiteTitle
Write-Host "Changing title to:" $SiteTitle
$web.Update()                                                                                                          
$web.Dispose()                                                                                                        
$site.Dispose()           
Write-Host "Finished!"
}

Second demo function – New-SPWebFromXml
XML Syntax:

<?xml version="1.0" encoding="utf-8"?>
<Sites>
  	<Site>
    		<SiteTitle>Ryan Dennis</SiteTitle>
	    	<SiteUrl>http://sps.adventureworks.com/rdennis</SiteUrl>
	    	<Page>
			<PageTitle>Home</PageTitle>
			<PageUrl>Home.aspx</PageUrl>
			<PageContent>HTML Content</PageContent>
			<PageLayout>Body Only</PageLayout>
		</Page>
  	</Site>
</Sites>

PowerShell code:

function New-SPWebFromXml {
# Xml Input parameter - accepts string to filename
[CmdletBinding()]
	Param(
    [Parameter(Mandatory=$true)]
	[string]$XmlInput
	)

# Read in list of sites from XML file
[xml]$SitesXml = Get-Content $($XmlInput)
if ($SitesXml -eq $null) {return}
Start-SPAssignment -Global #Stores all objects in the global store for proper disposal
$StartTime = Get-Date #Grab the date & time for further calculation later

# Upload speaker images to the PublishingImages library
Write-Host "Uploading speaker images to the PublishingImages library..."
Add-SPFilesToLibrary -WebUrl http://sps.adventureworks.com -LibraryName PublishingImages -FileExtension "*.jpg" -FolderLocation "C:\SPSDemo\Speakers"

	# Loop through each site node to extract data
	$SitesXml.Sites.Site | ForEach-Object {
	$SiteTitle = [string]$_.SiteTitle
	$SiteUrl = [string]$_.SiteUrl
	$WebTemplate = "CMSPUBLISHING#0"
	$LangId = "1033"
	
	# Get publishing site and web objects
	$site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
	$psite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($site)
	$web = $site.OpenWeb()
	$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
	
	# Create the SPWeb
	Write-Host "Creating an SPWeb at $($SiteUrl)"
	New-SPWeb -Url $SiteUrl	-Language $LangId -Template $WebTemplate -Name $SiteTitle
	
	# Create page content variables from XML file
	$PageTitle = [string]$_.Page.PageTitle
	$PageUrl = [string]$_.Page.PageUrl
	$PageLayout = [string]$_.Page.PageLayout
	$PageContent = [string]$_.Page.PageContent
	$PageImage = [string]$_.Page.PageImage
	$layout = $pWeb.GetAvailablePageLayouts() | Where-Object {$_.Title -match $PageLayout}
	
    # Create blank page using Add method
	Write-Host "Creating $($PageTitle).aspx page"
    $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.DefaultPage = $file
	$pWeb.Update()
	
	# Get and delete original default.aspx page
	Write-Host "Deleting default.aspx page"
	$list = $web.lists["Pages"]
	$oldPage = $list.items | Where-Object {$_.Name -match "default"}
	$oldPage.Delete();
	$web.Update()
	} #End ForEach-Object loop
	
$EndTime = Get-Date #Grab the ending date & time to get the timespan
$TimeSpan = New-TimeSpan $StartTime $EndTime #Calculate total time taken
Write-Host "$($SitesXml.Sites.Site.Count) sites created in $timespan"
Stop-SPAssignment -Global #Stop assignment, safely disposing all site and web objects
} #End Function

Bulk Creation of Pages using PowerShell


I’m working on an internet-facing project for my current client, and one of the largest tasks will be migrating approximately 1,500 pages from static HTML to SharePoint 2010 (.aspx) pages. While I have a migration staff which will do the majority of the heavy lifting, I still wanted to try and find a way to automate some of the work.

Obviously I reached out to the tool I love, PowerShell.

At first I did some searching, and I found a post by Brendan Newell that had a script for creating pages from XML.

This was a great start and contributed most of the code to my function. However, in Brendan’s script he mentions that he had no need to use a different page layout – or define any additional metadata. However, I wanted to do those things – so I adapted Brendan’s outstanding example into one I can use to pre-create pages that my migration staff can then populate with the real data.

Another thing I wanted was the ability to create a single page – so I adapted the function to solve two problems: Creating a single page, and creating multiple pages from XML input.

Using several parameters I’m able to accomplish these things pretty efficiently and effectively – I have 9 parameters total, they are:

  1. SiteUrl – This is simply the site to create the pages in.
  2. PageTitle – If creating a single page
  3. PageUrl – If creating a single page
  4. PageContent – If creating a single page
  5. PageLayout – If creating a single page
  6. Checkin – Switch parameter, checks in the page
  7. Publish – Switch parameter, publishes the page
  8. CreateFromXml – Switch parameter, tells the function to create using the XML portion of the function
  9. XmlInput – Path to the xml file containing the page information

Here is the (very large) function:

function New-SPPage{
<#
.Synopsis
	The New-SPPage function creates one or more Publishing Pages in a SharePoint Publishing Site.
.Description
	The New-SPPage function uses the PublishingSite and PublishingWeb objects to call the Add() method for provisioning of SharePoint Publishing Pages.
.Example
	C:\PS>New-SPPage -SiteUrl http://intranet `
	-PageTitle "My Page" `
	-PageUrl MyPage.aspx `
	-PageContent "This is my text." `
	-PageLayout "Article Page" `
	-CheckIn -Publish	
	This example creates a single page in the http://intranet site.
.Example
	C:\PS>New-SPPage -CreateFromXml -XmlInput "C:\Pages.xml" -Checkin -Publish
	This example creates pages based on an xml file with the following schema:
<?xml version="1.0" encoding="utf-8"?>
<Pages>
  <Page>
    	<PageTitle>Page 1</PageTitle>
        <PageUrl>Page1.aspx</PageUrl>
        <PageContent>
        This is some text.
        This is another line of text.
        </PageContent>
        <PageLayout>Article Page</PageLayout>
  </Page> 
</Pages>
.Notes
	Name: New-SPPage
	Author: Ryan Dennis
	Last Edit: 7/25/2011
	Keywords: New-SPPage
.Link
	http://www.sharepointryan.com
 	http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
#Requires -Version 2.0
#>
[CmdletBinding()]
	Param(
    [Parameter(Mandatory=$true)]
	[string]$SiteUrl,
    [Parameter(Mandatory=$false)]
	[string]$PageTitle,
    [Parameter(Mandatory=$false)]
	[string]$PageUrl,
	[Parameter(Mandatory=$false)]
	[string]$PageContent,
	[Parameter(Mandatory=$false)]
	[string]$PageLayout,
	[Parameter(Mandatory=$false)]
	[switch]$CheckIn,
	[Parameter(Mandatory=$false)]
	[switch]$Publish,
	[Parameter(Mandatory=$false)]
	[switch]$CreateFromXml,
	[Parameter(Mandatory=$false)]
	[string]$XmlInput
    )
#Region CreateFromXml
if ($CreateFromXml) {
# Read in list of pages from XML
[xml]$pagesXML = Get-Content $($XmlInput)
if ($pagesXML -eq $null) { return }
# Get publishing web
$site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
$psite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($site)
$web = $site.OpenWeb()
$pWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
# Loop through each page node to extract filename
$pagesXML.Pages.Page | ForEach-Object {
    $PageTitle = [string]$_.PageTitle
	$PageUrl = [string]$_.PageUrl
	$PageLayout = [string]$_.PageLayout
	$PageContent = [string]$_.PageContent
	$ctype = $psite.ContentTypes[$PageLayout]
	$layouts = $psite.GetPageLayouts($ctype, $true)
	$layout = $layouts[0]
    Write-Host "Creating $($PageTitle)"

    # Create blank page
    $pages = $pWeb.GetPublishingPages($pWeb)
	$page = $pages.Add($PageUrl, $Layout)
	#$newPage = $pWeb.AddPublishingPage($PageUrl,$PageLayout)
    $page.Update()

    # Update the filename to the one specified in the XML
    $item = $page.ListItem
	$item["Title"] = $PageTitle;
	$item["Page Content"] = $PageContent;
	$item.Update()
    # Check-in and publish page
    if ($CheckIn){$item.File.CheckIn("")}
    if ($Publish){$item.File.Publish("");}
} #End ForEach Loop
# Dispose of the web
$web.Dispose()
} #End CreateFromXml
#EndRegion CreateFromXml
#Region CreateSinglePage
else {
Start-SPAssignment -Global
$site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
$psite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($site)
$ctype = $psite.ContentTypes[$PageLayout]
$layouts = $psite.GetPageLayouts($ctype, $true)
$layout = $layouts[0]
$web = $site.OpenWeb(); #Site.Rootweb
$pweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$pages = $pweb.GetPublishingPages($pweb)
$page = $pages.Add($PageUrl, $layout)
$item = $page.ListItem
Write-Host "Creating $($PageTitle)"
$item["Title"] = $PageTitle;
$item["Page Content"] = $PageContent;
$item.Update() 
if ($CheckIn){$item.File.CheckIn("")}
if ($Publish){$item.File.Publish("")}
$site.Dispose()
$web.Dispose()
Stop-SPAssignment -Global
} #End single page from else
} #End function

Here is an example XML file:

<?xml version="1.0" encoding="utf-8"?>
<Pages>
  <Page>
    <PageTitle>Page 1</PageTitle>
	<PageUrl>PageOne.aspx</PageUrl>
	<PageContent>
	This is some text.
	This is another line of text.
	</PageContent>
	<PageLayout>Article Page</PageLayout>
  </Page>
  <Page>
    <PageTitle>Page 2</PageTitle>
	<PageUrl>PageTwo.aspx</PageUrl>
	<PageContent>
	&lt;strong&gt;This should be bold text!&lt;strong&gt;
	</PageContent>
	<PageLayout>Article Page</PageLayout>
  </Page>
</Pages>

Note | The second page has encoded HTML using the strong tag for the following result: