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:
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