Powershell script for updating a publishing page Page Layout in a site collection

One of the page layout templates was changed in a SharePoint 2010 site collection that I was working on.  There were already over 300 pages that were creating using the old Page Layout.  Enter… Powershell!  It took about two hours to write this script (with help from The Google) but it will probably save a day of work updating all those pages individually through the UI.

The script takes three parameters, the old or current page layout name, the new page layout name and an optional –all parameter which will traverse all the sites of a site collection.  Enjoy.

# Description:
# Update the layout page for all matching pages of the current page layout
# Checkout, Change layout, Check-in pages in a site collection
#
# Syntax:
# ./UpdateLayoutPages [-PageLayoutCurrent] [-PageLayoutNew] [-all]
#
# Parameters:
# -PageLayoutCurrent     - The page layout that is currently in use and will be updated
# -PageLayoutNew        - The new page layout that pages will be updated to
# -all                     - Update subsites in the site collection
#
# Modifications:
# v1.0 - April 5th, 2011
# Initial version
#
# Settings
set-variable -option constant -name url  -value http://localhost   # Site collection
set-variable -option constant -name comment -value "Batch PageLayout Update"   # Publishing comment

# Function: Update-SPPagesPageLayout
# Description: Update a single page in a Publishing Web
# Parameters: publishingPage, pageLayout, comment
function Update-SPPagesPageLayout ([Microsoft.SharePoint.Publishing.PublishingPage]$publishingPage,
    [Microsoft.SharePoint.Publishing.PageLayout] $pageLayoutNew, [string]$comment)
{
    Write-Host "Updating the page:" $publishingPage.Name "to Page Layout:" $pageLayoutNew.Title
    $publishingPage.CheckOut();
    $publishingPage.Layout = $pageLayoutNew;
    $publishingPage.ListItem.Update();
    $publishingPage.CheckIn($comment);
    if ($publishingPage.ListItem.ParentList.EnableModeration)
    {
        $page.ListItem.File.Approve("Publishing Page Layout correction");
    }
}

# Function: Update-AllSPPagesPageLayouts
# Description: Loop through all the pages in a Publishing Web and update their page layout
# Parameters: web, pageLayoutCurrent, pageLayoutNew, comment
# comment Comment to accompany the checkin
Function Update-AllSPPagesPageLayouts ([Microsoft.SharePoint.SPWeb]$web, [Microsoft.SharePoint.Publishing.PageLayout]$pageLayoutCurrent,
    [Microsoft.SharePoint.Publishing.PageLayout]$pageLayoutNew, [string]$comment)
{
    #Check if this is a publishing web
    if ([Microsoft.SharePoint.Publishing.PublishingWeb]::IsPublishingWeb($web) -eq $true)
    {
      $pubweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web);
      $pubcollection=$pubweb.GetPublishingPages()
      #Go through all pages checking for pages with the "current" page layout
      for($i=0; $i -lt $pubcollection.count; $i++)
      {
        if($pubcollection[$i].Layout.Title -eq $pageLayoutCurrent.Title)
        {
            Update-SPPagesPageLayout $pubcollection[$i] $pageLayoutNew $comment
        }
      }
    }
    $web.Close();
}

# Check Parameters
if(($args[0] -ne $null) -and ($args[1] -ne $null))
{
    Write-Host "** Update Layout Pages from-" $args[0] "-to-" $args[1] "-on URL" $url
    $pageLayoutNameCurrent = $args[0];
    $pageLayoutNameNew = $args[1];

    $site = new-object Microsoft.SharePoint.Publishing.PublishingSite($url)

    Write-Host "Checking if both page layouts exist in the site..."
    # Check if the current pagelayout exists in this site collection
    $pageLayouts = $site.GetPageLayouts($true);

    $pageLayouts | ForEach-Object {
        if ($_.Title -eq $pageLayoutNameCurrent)
        {
            Write-Host "Found CURRENT page layout: " $pageLayoutNameCurrent
            $pageLayoutCurrent = $_;
        }
    }

    # Check if the new pagelayout exists in this site collection
    $pageLayouts | ForEach-Object {
        if ($_.Title -eq $pageLayoutNameNew)
        {
            Write-Host "Found NEW page layout: " $pageLayoutNameNew
            $pageLayoutNew = $_;
        }
    }      

    # Do not continue if the either pageLayout does not exist
    if(($pageLayoutCurrent -ne $null) -and ($pageLayoutNew -ne $null))
    {
        # Update all subsites
        if($args[2] -eq "-all")
        {
         $site.Site.allwebs | foreach {
            Write-Host "Checking Web: " $_.Title
            Update-AllSPPagesPageLayouts $_ $pageLayoutCurrent $pageLayoutNew $comment
            }
        }
        else
        {
         $site.rootweb | foreach {
            Write-Host "Checking Web: " $_.Title
            Update-AllSPPagesPageLayouts $_ $pageLayoutCurrent $pageLayoutNew $comment
            }
        }
    }
    Write-Host "**Done"
}
else
{
    Write-Host "Missing arguments.  Please check your parameters"
}
#End
About these ads
  1. #1 by Sean Tuck on May 9, 2011 - 4:39 pm

    Hey Jake
    Thanks for the code. I have a similar issues I have to solve that I’m using your script as the base for. My issue is that I have multiple site collections that I need to move under one primary site collection as sub-sites, under SP 2010.

    I can export the site collection and import as a sub-site, but the page layout link is broken. I copied the page layouts and master pages to the primary site collection run and try to run this code to update the link for that page layouts. I get an error stating it could not update the Layout (Null Exception).

    If I detach the page layout from one of the pages using SharePoint Designer and rerun the code it works.

    My question is:
    “Is there a way to detach the page layout via code?”

    Thanks
    SeanTuck

  2. #2 by Yvan on May 31, 2011 - 7:13 pm

    One little missing line on the function. To actually reflect the updates on existing content pages that are using the layout, you’ll need to call the Update() method for the page itself right after the ListItem one…

    $publishingPage.Layout = $pageLayoutNew;
    $publishingPage.ListItem.Update();
    $publishingPage.Update();
    $publishingPage.CheckIn($comment);

    also I believe the approval line is also incorrect, because is using the $page instead of the $publishingPage object…

    $page.ListItem.File.Approve(“Publishing Page Layout correction”);
    $publishingPage.ListItem.File.Approve(“Publishing Page Layout correction”);

  3. #3 by Jagjit Assi on October 6, 2011 - 1:48 pm

    This worked very well for me. I had to change the approval line as suggested in another comment. One thing that I think it is missing is that it did not check if the pages are already checked out by someone. It gave me errors for those pages which were checked out by someone. It would be be nice to perform that check and report the checked out files.

    Another thing I changed in the script was the output method. I changed the Write-Host to Write-Output so that I could capture the output to a file using a pipe for example .\PageLayoutUpdate.ps1 “Page Layout” “Page Layout New” 2>&1 > c:\temp\test.txt

  4. #4 by Awenta Preston on November 3, 2011 - 12:01 pm

    Hi Chris, nice PS! I tried this but I could not figure out where I can put the name of the current pagelayot and the new of the new one I would like to apply to let say http://MyIntra/NewsSite/. I can change the variable under settings for the site, but how can I specify the name of the PageLayouts?
    One more question, what about to if you dont want to change the ‘home page’ for the site, let say I have 300 pages in the site, and I want to apply a new pagelayout for 299 pages and not the start page like http://MyIntra/NewsSite/Pages/Default.aspx mayby you can extend your script with this options?
    Thanks!

  5. #5 by Mike on November 22, 2011 - 12:02 pm

    Hi,
    I’m encountering the following errors:
    Cannot overwrite variable pageLayoutCurrent because it is read-only or constant.
    and
    Update-AllSPPagesPageLayouts : Cannot process argument transformation on parameter ‘pageLayoutCurrent’. Cannot convert the “Country Page” value of type “System.String” to type “Microsoft.SharePoint.Publishing.PageLayout”.

    Any ideas?

  6. #6 by Mike on November 22, 2011 - 12:50 pm

    Hi,
    Please ignore my last comment!!!

    The script is great and works fine… as long as you don’t let a junior dev do the typing! :-)

  7. #7 by augrad94 on January 28, 2013 - 8:25 pm

    This worked great with just the few minor tweaks listed above!

  8. #8 by augrad94 on January 28, 2013 - 8:37 pm

    Reblogged this on Hubert Anderson's Blog and commented:
    Nice time saver here!

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 98 other followers

%d bloggers like this: