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;

Get a Web, List and Library Inventory using PowerShell


A colleague of mine recently asked me “Ryan, can you give me some PowerShell code that can give me a list of all sites and sub sites as well as all lists and libraries within each of those sites – for an entire web application?”

“Of course”, I said…

I had some other scripts and functions that were similarly constructed, so I simply took one that was close and adapted it to make it work.

This function, which I’ve called “Get-SPSiteInventory” will run against either an entire Web Application (using the -WebApplication switch param) or a single Site Collection (using the -SiteCollection switch param).

I’ve tested this both by sending the output straight to a file (using the Out-File cmdlet) as well as just running in the shell – both work pretty nicely.

I’ve excluded comment-based help for better readability, and the syntax is as follows…

To run against a site collection:

Get-SPSiteInventory -Url http://spsite -SiteCollection

To run against a web application:

Get-SPSiteInventory -Url http://spwebapp -WebApplication

The entire function:

function Get-SPSiteInventory {
Param(
[string]$Url,
[switch]$SiteCollection,
[switch]$WebApplication
)
Start-SPAssignment -Global
	if ($SiteCollection) {
		$site = Get-SPSite $Url
		$allWebs = $site.allwebs
		foreach ($spweb in $allWebs) {
			" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
			$spweb.Url
			$spweb.Lists | select Title, BaseType
			$spweb.dispose()
		}
		$site.dispose()
	} 
	elseif ($WebApplication) {
		$wa = Get-SPWebApplication $Url
		$allSites = $wa | Get-SPSite -Limit all
		foreach ($spsite in $allSites) {
			$allWebs = $spsite.allwebs
			foreach ($spweb in $allWebs) {
			" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
			$spweb.Url
			$spweb.Lists | select Title, BaseType
			$spweb.dispose()
			}
		}
	}
Stop-SPAssignment -Global
}

Access Denied while creating Publishing Pages


I ran into one of those weird errors that just kind of gets under your skin because you think you’ve checked everything.

You’ve all seen Access Denied errors in SharePoint, but have you run into the one where users WITH proper permissions get it when trying to create a list item – in this case Publishing Pages? Very bizarre.

I checked all of the usual suspects, permission inheritance, draft items in Style Library, Master Page Gallery, etc. Nothing. But then when I reached out to the search engines just for giggles, I found this post by Gunnar Peipman which gave me exactly what I needed.

The permissions on the Master Page Gallery are unique, and users need at least “Restricted Read” to create pages. What’s frustrating is if you go into Site Permissions and view the Uniquely Secured Content, Master Page Gallery DOES NOT show up in that list. You’d think it would show you all uniquely secured content, but that’s not the case.

Thanks Gunnar for the short post with the fix!

1.Go to Site Actions -> Site Settings ->Modify all site settings
2.Go to Galleries -> Master pages and page layouts
3.From the list toolbar, select Settings -> Document library settings
4.Select permissions for this document library
5.Add ‘Restricted Read’ access to the required groups.

DAYSPUG Presentation December 13th 2011


Last night I spoke to a great crowd of PowerShell Enthusiasts at the Dayton SharePoint Users Group (DAYSPUG) in Dayton, Ohio. I knew most of the folks in attendance from other local SharePoint and PowerShell events, so it was nice to see everyone again.

It was a pleasure to speak in front of all of you, and I thoroughly enjoyed the engagement that you all showed.

Since the actual presentation/demo wasn’t much different from my recent engagement at SharePoint Saturday Cincinnati, I’ll simply point to that post for the actual PowerShell and XML code I used in the demos. That content is located here: SPS Cincinnati Post

Here is a post which contains the two Christmas functions I shared last night as well: Two PowerShell Functions for the Christmas Season

Thanks again to Tony Maddin and the rest of the DAYSPUG members for welcoming me to speak. See you all next time!

RD