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.

Advertisement

Get a SharePoint Publishing Content Inventory using PowerShell


There may be a time when you want to get an inventory of all publishing content (Sites, Documents, Pages, etc.) for an entire site collection. I needed to do exactly that, so I wrote a handy little PowerShell function that walks through a Publishing Site Collection – counting the webs, pages, images and documents.

Here is the function!

function Get-SPPublishingSiteInventory {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][string]$SiteUrl
)
    Start-SPAssignment -Global
    $Site = New-Object Microsoft.SharePoint.SPSite($SiteUrl)
	$PubSite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($Site)
	$PubPageCount = 0
	$ImageCount = 0
	$DocCount = 0
	foreach ($Web in $Site.AllWebs) {
        $PubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($Web)
		$Pages = $PubWeb.GetPublishingPages($PubWeb)
		$PageCount = $Pages.Count
		$PubPageCount = $PubPageCount + $PageCount
		$Images = $PubWeb.ImagesLibrary.ItemCount
		$ImageCount = $ImageCount + $Images
		$Documents = $PubWeb.DocumentsLibrary.ItemCount
		$DocCount = $DocCount + $Documents
		$Web.Dispose()		
    }
    $Site.Dispose()
    Write-Host "Number of Sites: "     $site.allwebs.count
    Write-Host "Number of Pages: "     $PubPageCount
	Write-Host "Number of Images: "    $ImageCount
	Write-Host "Number of Documents: " $DocCount
    Stop-SPAssignment -Global
}

Add Print Page Functionality Using JavaScript


This morning I received a request from my current client which I’ve gotten before, but not in SharePoint 2010.

They wanted the ability to print page and list view content easily, and without the left and top navigation elements – basically just the main content zone.

I knew there was a way as I had done this in 2007, but I had to do a quick search for the exact JavaScript.  I found a Codeplex project that included a Content Editor Web Part with JavaScript and this worked almost perfectly for my scenario.

This solution works great if you want to print a single page, but I wanted reusability and something that I could do once and have it work for every page in a site.

I ended up copying the script verbatim into a PrintScript.js file which I saved under /_layouts/1033, here is the code of the file:

<!-- Web Part/region to print -->
var WebPartElementID = "ctl00_MSO_ContentDiv";


//Function to print Web Part
function PrintWebPart()
{
 var bolWebPartFound = false;
 //var currentPage = document.location.href;
 if (document.getElementById != null)
 {
  //Create html to print in new window
  var PrintingHTML = '<HTML>\n<HEAD>\n';
  //Take data from Head Tag
  if (document.getElementsByTagName != null)
   {
   var HeadData= document.getElementsByTagName("HEAD");
   if (HeadData.length > 0)
    PrintingHTML += HeadData[0].innerHTML;
   }
  PrintingHTML += '\n</HEAD>\n<BODY>\n';
  var WebPartData = document.getElementById(WebPartElementID);
  if (WebPartData != null)
  {
   PrintingHTML += WebPartData.innerHTML;
   bolWebPartFound = true;
  }
  else
  {
   bolWebPartFound = false;
   alert ('Cannot Find Web Part');
  }
 }
 PrintingHTML += '\n</BODY>\n</HTML>';
 //Open new window to print
 if (bolWebPartFound)
 {
  var PrintingWindow = window.open("","PrintWebPart", "toolbar,width=800,height=600,scrollbars,resizable,menubar");
  PrintingWindow.document.open();
  PrintingWindow.document.write(PrintingHTML);
  // Open Print Window
  PrintingWindow.print();
 }
}

Once I had the JavaScript file saved in the layouts directory, I could simply add a ScriptLink tag in the <head> section of my master page:

<SharePoint:ScriptLink name="PrintScript.js" runat="server"/>

That’s great, now my master page has the ability to print any page; but where do I put the link?  At first I thought of adding a new DIV in the footer area of my page, but I didn’t want the Print link to be included in the printed version of the page.

A quick search on how to add an item to the Site Actions menu gave me EXACTLY what I wanted – and since this is an Intranet solution, every user that needs to print will have at least Contribute permissions and therefore will have the Site Actions menu available to them.

In order to display what I wanted in the Site Actions menu, I added the following code under the <CustomTemplate> section:

<!--Print item added to Site Actions -->
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_PrintPage"
	Text="Print this page"
	Description="This will launch a new window to print this page."
	ImageUrl="/_layouts/images/Print.png"
	MenuGroupId="100"
	Sequence="110"
	ClientOnClickNavigateUrl="javascript:PrintWebPart();"
	/>
<!--End print item-->

And finally, here is what I’m left with:

And clicking the Print Page option gives me a nice, clean window with no navigational elements:

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: