Configuring Custom 404 Pages using PowerShell


I came across an interesting challenge while working on my current project; which is a migration from a classic HTML-based website to SharePoint 2010 For Internet Sites, Enterprise.  Custom error pages…

Out of the box, SharePoint likes to give the user a useless 404 error like this:

image

While there is out-of-the-box support for custom error pages in SharePoint 2010, it’s not completely obvious how you set the custom error pages for a web application.  First of all, SharePoint includes an sps404.html page in the /_layouts/{language} folder which by default includes an STSNavigate reference to handle the redirect.  That’s all well and good, but I want my own!

Here’s how I got what I wanted:

Copy the sps404.html page and rename it to sps404custom.html – leave the new file in the same location.  Open the file in your favorite HTML editor and look for the STSNavigate line – change the link to an appropriate page, example /Pages/Page-Not-Found.aspx.

This would replace the OOTB 404 behavior with an automatic redirect to a Publishing page under the root Pages library of my web application.  Cool!

Now I just have to create a page at /Pages/Page-Not-Found.aspx and add some text.  The page will inherit whatever branding elements I’ve applied to the rest of my site, leaving the user with a much cleaner and consistent experience.  Once I’ve done those two things, there’s a little PowerShell that must be done to actually set the custom 404 page:

$WebApp = Get-SPWebApplication http://url
$WebApp.FileNotFoundPage = "sps404custom.html"
$WebApp.Update() 

Once that’s done, try going to a bogus page in your site and you should be taken to your custom 404 page!

image

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: