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
#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 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 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 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 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 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 by augrad94 on January 28, 2013 - 8:25 pm
This worked great with just the few minor tweaks listed above!
#8 by augrad94 on January 28, 2013 - 8:37 pm
Reblogged this on Hubert Anderson's Blog and commented:
Nice time saver here!