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.Update()
    $publishingPage.CheckIn($comment);
    if ($publishingPage.ListItem.ParentList.EnableModeration)
    {
        $publishingPage.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
  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!

  9. #9 by Jeremy Rueter on June 30, 2016 - 3:17 pm

    I’m trying to use this script but I don’t know Powershell well enough. I’m sure the following question is extremely basic.

    Where/how do I specify the parameters? It seems like the function looks for certain parameters such as $pageLayoutNew. Where/how do I specify what exactly that page layout is? There must be some way to provide a link or a file name or something.

    I’m just not experienced enough with Powershell to know.

    Thanks in advance for any help.

    • #10 by Jake on June 30, 2016 - 4:03 pm

      Hi Jeremy. I made the assumption that you would name your PowerShell script file “UpdateLayoutPages.ps1” That was not a great assuption. But, if you do then you’d load the script that way through your PowerShell command shell. So something like this… PS C:\PSScripts> .\UpdateLayoutPages.ps1 myOutOfDatePage.aspx SingleColumnLayout.aspx

      I’m specifying the parameters on the command line here, but I could also do it in another PowerShell file (say UpdateTenPages.ps1) and call UpdateLayoutPages.ps1 10 times for 10 different pages. Does that help? It’s a good question and points out that I named my PS1 file UpdateLayoutPages.ps1, which I never mentioned. Thanks!

  10. #11 by Jeremy Rueter on June 30, 2016 - 5:32 pm

    Hi Jake. Thank you for your quick response. I’m sure your instructions were fine for anyone with Powershell experience. Now that you’ve given an example it makes sense.

    I’m able to run the script. It checks the parameters and I get a message about “checking if both pages layout exist in the site” and then a “Done” message. However none of the page layouts are actually changed.

    Anything else you can think of that I should check? Anything else I haven’t specified? Maybe a permissions issue?

  11. #12 by Jake on June 30, 2016 - 6:04 pm

    Hi Jeremy. This script does not check the files in (I think). Are your files checked in and approved?

    • #13 by Jeremy Rueter on June 30, 2016 - 8:29 pm

      Hi Jake. Thanks again for your quick reply.

      It looks to me like your script actually does check out, check in, and approve items.

      If I’m following the code correctly, right after the “Checking if both page layouts exist in the site…” message it then should check if the parameter I’ve listed as the current page layout actually exists in the site collection. And after checking it I should see “Found CURRENT page layout: ” I don’t see that. It just skips down to “done”. I’ve entered incorrect page layouts but it still just skips down to “done”.

      Do you know if there is a way to output to a log file? Maybe that could show me an error message that I’m not able to see otherwise?

      Thanks again for taking the time to reply to a 5-year-old post.🙂

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 100 other followers

%d bloggers like this: