New Issue with STSADM MergeContentDB
I just saw this post on the SharePoint forums: http://social.msdn.microsoft.com/Forums/en-US/sharepointgeneral/thread/e9cd9836-5a50-42b3-bf2f-02338a3168f3 – it appears that there’s a possibility for data corruption when using the STSADM mergecontentdb command. The post details a few things you can do to reduce the possibility of corruption when using the command but it would appear that the hidden message is to use Backup/Restore until a fix is released.
Don’t Use the PrepareToMove STSADM Command
Todd Carter just published an interesting post about when to use, and more appropriately, not use the preparetomove command: http://blogs.msdn.com/toddca/archive/2009/01/30/preparetomove-away-from-running-this-command.aspx. Essentially if you have at least the Infrastructure Update (IU) installed then using this command will cause you issues. See Todd’s post for more details.
gl-fixpagecontact Deprecated!!!
Woohoo! – I finally get to deprecate one of my commands – after creating and publishing 135 commands I discovered today that the August Cumulative Update fixes the issue that my gl-fixpagecontact command sought to address. If you look back at the post for that command you can see that there was a bug with the product which resulted in a user not found exception being thrown when looking at the settings of a publishing page. This happened in couple of different situations but the easiest way to trigger it was to simply delete the user that created the page (or that was assigned as the page contact or that last modified the page) from the site collection. When you did this and then visited the settings page you would get an error similar to the following:
The error would vary slightly depending on whether or not the field was the “Contact”, “CreatedBy”, or “LastModifiedBy” field. I decided to revisit this command due to a comment that was posted on the post related to it which asked if the command could be modified to handle the CreatedBy and LastModifiedBy fields (I was only handling the Contact field). I did some digging and have not yet discovered a way to update these two fields for a document library (if anyone has a way to do this please let me know) so I decided to send an email out to Paul Andrew to see if the bug had already been addressed - I usually pay attention to what fixes went into each update but I guess I missed this because within just a few minutes I got a response from Paul stating that this was indeed fixed with the August update (http://support.microsoft.com/kb/956056 and http://support.microsoft.com/kb/956057). So I decided to go ahead and update my development machine to confirm this and Merry Christmas it worked! After the updates got installed the settings page loaded fine and the invalid fields were set to my system account – now I’m not sure what logic is used here to determine what user is used – I was logged in with my system account so I don’t know if it’s using the logged in user or the system account but regardless, the page loads and that’s the important part.
So I am now officially deprecating this command – I’ll keep it in with the package but I won’t be supporting it further now that I can finally tell people to just install the update! Thank you Paul for your help and quick responses!!!
Windows Server 2008 Default Impersonation Level Must Be Identify
If you're configuring a Windows Server 2008 environment with SharePoint 2007 and are planning on using Kerberos make sure that you do NOT set the default impersonation level for the server to delegate as recommended in this support article: http://support.microsoft.com/kb/953130 (note that Microsoft is working on updating this support article to reflect the differences with Windows Server 2008). If you do make this change then you will run into all kinds of issues with timer job related activities such as creating web applications and applying hotfixes or service packs.
The following is an example of what you'll find in your log files if you attempt install a hotfix or service pack:
SPHierarchyManager] [DEBUG] [8/5/2008 1:00:48 PM]: ------------------- Begin Growing Tree -------------------
[SPManager] [DEBUG] [8/5/2008 1:00:48 PM]: Using cached [SPWebApplication Name=SharePoint Teams (80) Parent=SPWebService] CanUpgrade value: True.
[SPManager] [DEBUG] [8/5/2008 1:00:48 PM]: Using cached [SPWebApplication Name=SharePoint Teams (80) Parent=SPWebService] NeedsUpgrade value: False.
[SPManager] [ERROR] [8/5/2008 1:00:48 PM]: Upgrade [SPWebApplication Name=SharePoint Teams (80) Parent=SPWebService] failed.
[SPManager] [ERROR] [8/5/2008 1:00:48 PM]: Access is denied.
[SPManager] [ERROR] [8/5/2008 1:00:48 PM]: at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_IsContainer()
at System.DirectoryServices.DirectoryEntries.ChildEnumerator..ctor(DirectoryEntry container)
at System.DirectoryServices.DirectoryEntries.GetEnumerator()
at Microsoft.SharePoint.Administration.SPIisWebSite.LookupByServerComment(String serverComment, Int32& instanceId)
at Microsoft.SharePoint.Administration.SPWebApplication.GetLocalIisWebSites()
at Microsoft.SharePoint.Upgrade.SPWebApplicationSequence.AddNextLevelObjects()
at Microsoft.SharePoint.Upgrade.SPHierarchyManager.Grow(SPTree`1 root, Boolean bRecursing)
at Microsoft.SharePoint.Upgrade.SPHierarchyManager.Grow(SPTree`1 root)
at Microsoft.SharePoint.Upgrade.SPManager.Upgrade(Object o, Boolean bRecurse)
The following is an example of some of the errors you may find in your event logs as the result of various timer job failures:
Log Name: Application
Source: Windows SharePoint Services 3
Date: 7/21/2008 5:34:52 PM
Event ID: 6398
Task Category: Timer
Level: Error
Keywords: Classic
User: N/A
Computer: Test-SPWFE1
Description:
The Execute method of job definition Microsoft.Office.Server.Administration.ApplicationServerAdministrationServiceJob (ID 7d6130ec-41cf-4c9c-9fe2-1d1d43c276e0) threw an exception. More information is included below.Access is denied.
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Windows SharePoint Services 3" />
<EventID Qualifiers="0">6398</EventID>
<Level>2</Level>
<Task>964</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2008-07-21T23:34:52.000Z" />
<EventRecordID>3106</EventRecordID>
<Channel>Application</Channel>
<Computer>Test-SPWFE1</Computer>
<Security />
</System>
<EventData>
<Data>Microsoft.Office.Server.Administration.ApplicationServerAdministrationServiceJob</Data>
<Data>7d6130ec-41cf-4c9c-9fe2-1d1d43c276e0</Data>
<Data>Access is denied.
</Data>
</EventData>
</Event>-------------------------------
Log Name: Application
Source: Office SharePoint Server
Date: 7/21/2008 5:34:52 PM
Event ID: 7076
Task Category: Office Server Shared Services
Level: Error
Keywords: Classic
User: N/A
Computer: Test-SPWFE1
Description:
An exception occurred while executing the Application Server Administration job.Message: Access is denied.
Techinal Support Details:
System.Runtime.InteropServices.COMException (0x80070005): Access is denied.at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_IsContainer()
at System.DirectoryServices.DirectoryEntries.CheckIsContainer()
at System.DirectoryServices.DirectoryEntries.Find(String name, String schemaClassName)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.Find(String name)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.get_Item(String name)
at Microsoft.SharePoint.Administration.SPProvisioningAssistant.ProvisionIisApplicationPool(String name, ApplicationPoolIdentityType identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.SharePoint.Administration.SPMetabaseManager.ProvisionIisApplicationPool(String name, Int32 identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.Office.Server.Administration.SharedWebServiceInstance.CreateSharedWebServiceApplicationPool(SharedResourceProvider srp)
at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob)
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Office SharePoint Server" />
<EventID Qualifiers="0">7076</EventID>
<Level>2</Level>
<Task>1328</Task>
<Keywords>0x80000000000000</Keywords>
160; <TimeCreated SystemTime="2008-07-21T23:34:52.000Z" />
<EventRecordID>3105</EventRecordID>
<Channel>Application</Channel>
<Computer>Test-SPWFE1</Computer>
<Security />
</System>
<EventData>
<Data>Access is denied.
</Data>
<Data>System.Runtime.InteropServices.COMException (0x80070005): Access is denied.at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_IsContainer()
at System.DirectoryServices.DirectoryEntries.CheckIsContainer()
at System.DirectoryServices.DirectoryEntries.Find(String name, String schemaClassName)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.Find(String name)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.get_Item(String name)
at Microsoft.SharePoint.Administration.SPProvisioningAssistant.ProvisionIisApplicationPool(String name, ApplicationPoolIdentityType identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.SharePoint.Administration.SPMetabaseManager.ProvisionIisApplicationPool(String name, Int32 identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.Office.Server.Administration.SharedWebServiceInstance.CreateSharedWebServiceApplicationPool(SharedResourceProvider srp)
at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob)</Data>
</EventData>
</Event>----------------------------------
Log Name: Application
Source: Office SharePoint Server
Date: 7/21/2008 5:34:51 PM
Event ID: 6482
Task Category: Office Server Shared Services
Level: Error
Keywords: Classic
User: N/A
Computer: Test-SPWFE1Description:
Application Server Administration job failed for service instance Microsoft.Office.Server.Search.Administration.SearchAdminSharedWebServiceInstance (c8e14f74-dd92-4c7e-8ab0-f696e65886e5).Reason: Access is denied.
Techinal Support Details:
System.Runtime.InteropServices.COMException (0x80070005): Access is denied.at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_IsContainer()
at System.DirectoryServices.DirectoryEntries.CheckIsContainer()
at System.DirectoryServices.DirectoryEntries.Find(String name, String schemaClassName)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.Find(String name)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.get_Item(String name)
at Microsoft.SharePoint.Administration.SPProvisioningAssistant.ProvisionIisApplicationPool(String name, ApplicationPoolIdentityType identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.SharePoint.Administration.SPMetabaseManager.ProvisionIisApplicationPool(String name, Int32 identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.Office.Server.Administration.SharedWebServiceInstance.Synchronize()
at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob)
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Office SharePoint Server" />
<EventID Qualifiers="0">6482</EventID>
<Level>2</Level>
<Task>1328</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2008-07-21T23:34:51.000Z" />
<EventRecordID>3104</EventRecordID>
<Channel>Application</Channel>
<Computer>Test-SPWFE1</Computer>
<Security />
</System>
<EventData>
<Data>Microsoft.Office.Server.Search.Administration.SearchAdminSharedWebServiceInstance</Data>
<Data>c8e14f74-dd92-4c7e-8ab0-f696e65886e5</Data>
<Data>Access is denied.
</Data>
<Data>System.Runtime.InteropServices.COMException (0x80070005): Access is denied.at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_IsContainer()
at System.DirectoryServices.DirectoryEntries.CheckIsContainer()
at System.DirectoryServices.DirectoryEntries.Find(String name, String schemaClassName)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.Find(String name)
at Microsoft.SharePoint.Metabase.MetabaseObjectCollection`1.get_Item(String name)
at Microsoft.SharePoint.Administration.SPProvisioningAssistant.ProvisionIisApplicationPool(String name, ApplicationPoolIdentityType identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.SharePoint.Administration.SPMetabaseManager.ProvisionIisApplicationPool(String name, Int32 identityType, String userName, SecureString password, TimeSpan idleTimeout, TimeSpan periodicRestartTime)
at Microsoft.Office.Server.Administration.SharedWebServiceInstance.Synchronize()
at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob)</Data>
</EventData>
</Event>
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:
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
BUG: Absolute Path Information Required
I got an interesting email the other day from Chakir Said regarding a bug that he encountered with SharePoint. He mis-typed the folder path for the web application and unfortunately the UI page has no validation to make sure that a valid path was specified. The result was that a web application was partially created and the invalid path was preventing the web application from being deleted - any attempts to delete would result in the error "Absolute Path Information Requried". This is because the get accessor of the Path property of the SPIisSettings object does a FileIOPermission check on the path which fails with the invalid (the set accessor does not do this check so it allows an invalid path to be set). Fortunately the fix turned out to be pretty simple - just set the Path property so something known and then call update on the web application. I've included the core code below (assumes you already have webApp set to the SPWebApplication object in question):
1: foreach (SPIisSettings iis in webApp.IisSettings.Values)
2: {
3: try
4: {
5: DirectoryInfo path = iis.Path;
6: if (!path.Exists)
7: throw new Exception();
8: }
9: catch (Exception)
10: {
11: iis.Path = new DirectoryInfo("c:\\");
12: webApp.Update();
13: }
14: }
SPLimitedWebPartManager.Dispose() bug
I found what I believe to be a bug and figured I’d pass along my findings. If you’re working with the SPLimitedWebPartManager object and call Dispose() on it there’s a minor problem – the Dispose() method does not dispose of the SPWeb object that gets loaded up – if you’re only using one instance this isn’t much of a problem but if you’re doing a lot of looping then you’ll eventually run out of memory on the server.
I have an stsadm command that I created which replaces content within web parts throughout a site – eventually the command fails because there’s not enough memory – I solved my issues by calling manager.Web.Dispose() (where manager is an SPLimitedWebPartManager object) right before calling manager.Dispose(). I also noticed that it doesn’t dispose of the web parts in the SPLimitedWebPartCollection object though this didn’t seem to be causing me any problems but I think it’s because I was already disposing of them when I was finished processing.
