MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Thursday, May 1, 2008

Fixing Invalid Page Contacts

Update 12/29/2008:  This command has been deprecated – the issues described below have been resolved with the August 2008 Cumulative Update (http://support.microsoft.com/kb/956056 and http://support.microsoft.com/kb/956057).

I've been doing a lot of migration work these days and if you've ever had to migrate content from one farm (or site collection) to another you know that all sorts of things can go wrong (many of which have been documented in one form or another on this blog).  One of the issues I've recently come across is related to the contact settings for a publishing page.  There are two ways in which this setting can become invalid and in both circumstances there is no way to fix the problem without using either SharePoint Designer or code (the invalid contact results in an error being thrown when trying to view the Page Settings and Schedules page).

The first way to end up with an invalid contact is to simply delete the contact from the list of users in the site collection.  Now, whether or not you should ever delete users is a topic for a different post but if you delete the contact that is associated with a page and then try to view the Page Settings and Schedule page you will see the following "User cannot be found" error:

Error: User cannot be found.

It's pretty frustrating that the page isn't sensitive enough to realize the contact is invalid and therefore either clear the setting or display some warning but at least let me load the page so that I can fix the error without having to crack open SPD.

The second way that this error can manifest itself is via a content migration.  For example - you have a valid contact assigned to the page in your test or staging environment and then you migrate the page to your production environment which is on a different domain and thus the page contact does not exist in that domain.  This is the scenario that I've been dealing with and because I've been moving pages in bulk I needed a better way than to use SPD every time I migrated a page - I wanted to be able to fix the issues as part of my deployment script.  The result is a new command I created called gl-fixpagecontact.

To better understand why the contact can become invalid (even in a migration scenario where your usernames are the same in both domains) it's important to understand how the information is stored.  The contact information is stored in the "Contact" (FieldId.Contact) field of the pages SPListItem object and the format is the users ID followed by ";#" (without the quotes) followed by the users display name: 20;#Test User

The ID shown is (obviously) not the SID of the user but rather the ID of the user in the site collections users list and obviously this ID will vary from one farm to another (and even from one site collection to another).  Note that if you delete a user from the site collection and then add them back in their ID will be set to the original ID so to fix the first scenario you can simply re-add the user, fix the contact for the page manually and then re-delete the user.

So what does my new command do?  It parses the data in the field (splits on ;#) and uses the display name to try and find a principle that matches the principle regardless of the ID.  If it can't find a match then it will replace the contact with either the current user or a user provided via the "-contact" parameter.  Note that you can also use this command to force all pages to have a contact set - it is not invalid to have an empty contact but your business rules may require that all pages have a contact set.  If you don't pass the "-allowempty" flag it will force the contact to be set to either the current user or a named user (via the -contact parameter).

Here's the syntax of the command:

C:\>stsadm -help gl-fixpagecontact

stsadm -o gl-fixpagecontact


Fixes the Page Contact property of a publishing page or pages if the current contact is invalid.

Parameters:
        -url <url>
        -scope <WebApplication | Site | Web>
        [-pagename <the name of the page to update>]
        [-contact <DOMAIN\name (contact user name to assign to the page - if not provided the current user is used)>]
        [-allowempty (allow empty contact values)]
        [-verbose]
        [-test]

Like many of my commands that do mass updates of data I provide a "-test" parameter so that you can simulate the execution and see what it would have changed without having it actually make changes - this is useful for just identifying your problem pages.  Here's a simple example of how you would run this command to fix all pages in a given site collection:

stsadm -o gl-fixpagecontact -url http://demo -scope site -allowempty -verbose

If you want to just fix a single page in a single web you would run the following:

stsadm -o gl-fixpagecontact -url http://demo -scope web -pagename default.aspx -verbose

12 comments:

Jesse Murray said...

http://stsadm.blogspot.com/2007/08/fix-publishing-pages-page-layout-url.html

http://stsadm.blogspot.com/2008/05/fixing-invalid-page-contacts.html

I've been working with these specific extensions in a multiple environment client situation. I've noted an incredible behavior that happens when the items run and fail, that the entire site collection becomes non-responsive.

This isn't a request for help, as it appears I found the cause, or atleast the solution to a cause. It seems when run in test mode, and the command encounters a checked-out file, the command ends. The site becomes non-responsive to the point where the only available interaction was command line or SharePoint designer. Simply undoing the check-out and re-running the command "fixes" whatever was hung and everything returns to normal operating and the contacts and publishing layouts are repaired.

Just thought I should pass this along in case you had seen similar behavior as I had not seen all of SharePoint for a single site collection stop running previously.

Ryan McGuire said...

I have two questions:

1. How do you mass change the pagelayout used by all the pages in a site AND all the subsites under that site. I tried -scope site, bu that started at my root site. I also tried -scope web, but that only did the site given in the -url but none of the subsites.

2. There's an option to change the page contact, is there a way to change the page creator?

Gary Lapointe said...

Currently the code that does the replacement won't recurse through sub-sites if the scope is web. My recommendation would be to use a simple powershell script to loop through all the webs and call out to the command. As far as updating the creator - no, I don't have anything to do this but you could easily modify the code to update the field.

tripwire said...

The Page Creator appears to be a major blocker in this scenario as well.

In our scenario 3rd party developers created all the original content using personal login credentials. When they finished the job, these users were removed from our production environment. This prevented accessing Page Settings for all pages.

Running the fixpagecontact command only does half the job.

If you're fixing the Page Contact it makes sense to check/update other fields for an invalid user as well.

Perhaps a separate command? People like myself are unfortunately not skilled or brave enough to modify the code to do this. :)

Gary Lapointe said...

Download the latest version - I've added an option to fix the CreatedBy and LastModifiedBy fields.

Thomas Hildebrandt said...

Hi Gary,

I tested the new function to fix the CreatedBy field. But it doesn't work for me. The output in the command line said that the contact is set.

But when I look into the DispForm of the page with the "User cannot be found error" the CreatedBy field hasn't changed.

The error still occurs.

Any ideas?

Thanks in advance,

Thomas

Gary Lapointe said...

Did you use the new -fixcreatedby and -fixlastmodifiedby parameters?

Thomas Hildebrandt said...

Hi Gary,

yes I used these parameters and in the CreatedBy-Column no changes was made by the stsadm cmd. There is still the "old" user.

Allthoug the cmd shown a success message that the user was set to the logged in user.

Any other ideas?

Thomas

Gary Lapointe said...

Thomas - been looking into this and there appears to be no way to set the createdby and lastmodified fields for a document library item - the code I had would set the field and update it but the value would not persist (been asking around and nobody seems to have a solution to this - appears to be by design). However, I did confirm that this issue is resolved with the August Cumulative Update - install the update and you'll be good to go (without needing my command). For now I'm going to revert my code to remove the addition of the two new parameters as they are having no affect.

tripwire said...

Hi Gary,

I wouldn't be so quick to deprecate the gl-fixpagecontact command. It just saved my life and we were running the mega Feb cumulative patch.

What's weird is that none of our pages had a contact!

I don't know what this code does but there's certainly some magic to it. :)

Vinny Tang said...

Hi Gary,

I perhaps didn't understand your post about -fixcreatedby and -fixlastmodifiedby that you commented about in Dec. Is that part of the gl-fixpagecontact command?

Gary Lapointe said...

No. I tried to get them to work but there's no way to change them.