Friday, February 27, 2009

Windows SharePoint Service 3 Search finds not matches after migrate users

I find the Windows SharePoint Services 3.0 Search to be a royal pain in the butt to work with.

However, one issue gave me trouble for weeks. I read all kinds of blogs, message boards, etc and tried everything I could think of or had read. Nothing worked.

Once I figured out how to find the crawl log (
see here) it wasn't so bad.

After reviewing the log in the Search database, I determined that the error message was:

Error in the Site Data Web Service. (Value does not fall within the expected range.)

Once I found this out, a google search returned a KB 941422, a hotfix.

The hotfix addresses my problem, which was that one site collection was being indexed, but another site collection was always returning no matches found when I did a search. I found out that there is a known bug that occurs when using the stsadm -o migrateuser command line to migrate users from one domain to another domain.

The hotfix is not tested as thoroughly as a service pack would be so Microsoft makes you request it. The url to request the hotfix is:

http://support.microsoft.com/kb/941422

A backup is always recommended. This includes your 12 hive since this is where most if not all the files reside that will be replaced.

One thing to be aware of when you download the hotfix. There is a 64bit and 32bit version (typically used). The download page only shows the 32bit version unless you tell it to show all platforms. If you try to run the wrong one, it will tell you it can't find the required product on the server.

One last thing, at first I did not think the hotfix worked since I tried the search and it didn't find any matches. The next day however, the same search did return results. So, I expect the content had to be reindexed after the hotfix was applied. Use the MSSCrawlHostList as explained
here.

Troubleshooting Windows SharePoint Services 3 Search using the logs.

Windows SharePoint Services 3.0 (WSS3)uses the same basic technology the Microsoft Office SharePoint Server 2007 (MOSS) uses. MOSS has a pretty good UI for determining the status of queries, configuration, etc. However, WSS3 does not provide much interface for anything when it comes to the search engine. In particular, I wanted to find out why a particular url was not being indexed.

I figured it must be somewhere in a database or log file. So, I looked in the log files (usually located at

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS

) and did see anything there. I looked in the Windows Event log and didn't find anything there. So, the only place left was the database. You should have a Search database (the database that has the word Search in it is usually the database you are looking for).

I found the MSSCRawlUrlLog table in the Search database. I found that it has a DisplayUrl column that will tell you what it tried to index. It has a column called ErrorDesc and an ErrorID column. I initially thought that the ErrorDesc was just description from the MSSCrawlErrorList (a look up table of all possible error ids), but it isn't. It is actually some other error description. Both error messages can be useful, however I find the one from the MSSCrawlErrorList table to be the most useful. Here is the query that takes all this into consideration.

select DisplayURl, l.ErrorDesc, el.ErrorMsg, LastTouchStart, HostID, StartAddressID from MSSCrawlUrlLog l
left outer join MSSCrawlErrorList el on (l.ErrorID = el.ErrorID)

order by DisplayURL,
LastTouchStart

If you want to take know what the coHostID lumn maps to, just look at the MSSCrawlHostList table. It also has an overview of crawl status. Here is a very simple, but useful query that tells you for each host the Success, Error, and Warning counts.

select * from dbo.MSSCrawlHostList

Thursday, February 26, 2009

Deleting object from SharePoint configuration database

I learned today that there is a very useful, but semi-hidden command that STSADM has called deleteconfigurationobject. From what I can tell, it deletes an object from the configuration database. Use caution when using this. I have used it when I need to delete a web site, web site application pool, database from the configuration database so that I can create a new one. This is particularly helpful when something gets corrupt.

The syntax is

STSADM -o deleteconfigurationobject -id "<object id>"

To figure out what the object id is, you will need to use SQL.

To find the object id easiest way is to just search by the common name of the object. To do that, follow these instructions.

  1. Open MS SQL Management Studio and open a new Query tab for the configuration database. Typically, this is the database with Config in it. Depending on the installation of SharePoint this could have been set to something else when it was installed.
  2. Do a query similar to the following
    select id from [Objects] where [Name] like '%MySite%'
  3. Copy the id, which is a GUID, and execute the STSADM -o deleteconfigurationobject -id command on the SharePoint server.

Monday, February 23, 2009

Make Tiny Time Tracker launch faster!

I like the Tiny Time Tracker application available from Source Forge that allows you to easily track how much time you spend on different tasks or projects. I highly recommend it. Its interface is very simple, but powerful. It basically has a drop down list that floats above all other windows. You can position it anywhere. You can shift time from one project to another if you forget to change it when you actually switched projects. It even stores the data to Excel. So, you get a very good reporting tool without any exporting. So, what is the problem you ask. Well, quite simply it takes way too long to open up. It takes like 30 seconds to open sometimes. If it is when I boot, it is even worse, but that is probably because of all the start up apps I have. In my mind, this is a very simple application that should open in like 1-3 seconds, not 15 to 30 seconds. I think the problem is Java WebStart. It looks for updates before it loads the local copy. Plus, just opening WebStart takes many seconds. I decided to see how fast the application launches if I run the jar directly. I was very happy with the results. It launched in 1 to 2 seconds!!! The problem with the default installation of Tiny Time Tracker is that what you actually download is a .jnlp file. All this file does is tell the WebStart application where to download the latest copy from. What we need is the .jar file, not the .jnlp file. If you want your Tiny Time Tracker application to launch extremely fast, I recommend doing the following:
  1. Go to the CVS repository and select tinytimetracker.jar and download the latest tinytimetracker.jar. You will probably need to download poi-3.5-beta3-20080926.jar if you don't have it.
  2. You can put the tinytimetracker.jar file anywhere on your system. For simplicity, I assume you are putting it at c:\TinyTimeTracker\tinytimetracker.jar.
  3. Using Windows Explorer, navigate to the C:\TinyTimeTracker directory.
  4. Right-click and choose New | Shortcut.
  5. For the location of the item field that comes up, just enter the following: javaw -cp "C:\TinyTimeTracker\tinytimetracker.jar" tracker.Tracker
  6. Name the shortcut whatever you want to.
  7. Now you can double-click the shortcut and Tiny Time Tracker will launch much faster than it ever did using Java WebStart.
If you have any problems, you can also run the same command from the command line. This will give you more information.

Wednesday, February 18, 2009

Numeric Keypad does work in Parallels

Well, to be fair the numeric keypad does work in Parallels, but it takes a little knowledge. What I found out is that when I run Windows XP in Parallels it looks to see if the num-lock is turned on or off. Just like a regular PC running Windows, the numeric keypad moves the cursor instead of typing numbers if the num-lock is off.

I guess the Mac OSX doesn't really have a concept of num-locks (at least when using the Apple keyboard). So, Parallels changed the clear key (near top left of numeric keypad) to be the num-lock toggle key. All you have to do is hit the clear key while in Windows XP (under Parallels) and you can toggle your num-lock.

Not very intuitive, but hey, what do you expect when you mix Mac and Windows together. ;)

Programmatically Updating a SharePoint Content Editor Web Part

I found it to be a bit tricky to programmatically update a SharePoint's Content Editor Web Part. Well, most properties of the web part are not an issue, however the Content property can be a bit tricky. The reason is because it is of type XmlElement. When I first started to look at doing this, I figured I could just modify the XML and call the SaveChanges() method. It is not that simple. If you don't set the Content property explicitly, that property is not marked dirty and therefore is never saved. Or at least that is my theory. The fact is that you must create a new XmlElement and set the Content property equal to it. If you do this you should have no problem.

Below is a sample method that I used to replace content on ALL Content Editor Web Parts that are on the particular SPWeb (based on the url passed). You could loop through all the SPWebs to do a global search and replace as well.

This method is not robust from a functionality standpoint. It is really just to illustrate how to get a reference to a webpart, make a not so straight forward change, and then persist the changes. For example, this method does not work on any pages that you add or that are not default.aspx. This code could be easily modified to do so though.

using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
...

public void SearchAndReplaceInContentEditorWebParts(string siteUrl, string oldString, string newString)
 {
  using (SPSite site = new SPSite(siteUrl))
  {
   using (SPWeb web = site.OpenWeb())
   {
    if (web.Exists)
    {
     using (SPLimitedWebPartManager mgr = web.GetFile("default.aspx").GetLimitedWebPartManager(PersonalizationScope.Shared))
     {

      if (mgr != null)
      {
       foreach (Microsoft.SharePoint.WebPartPages.WebPart part in mgr.WebParts)
       {
        try
        {
         if (part.GetType().ToString().Equals("Microsoft.SharePoint.WebPartPages.ContentEditorWebPart"))
         {
          ContentEditorWebPart contentEditor = (ContentEditorWebPart)part;

          // create a new XmlElement and put the results there
          XmlDocument xmlDoc = new XmlDocument();
          XmlElement xmlElement = xmlDoc.CreateElement("MyElement");
          xmlElement.InnerText = contentEditor.Content.InnerText.Replace(oldString, newString);

          // we MUST set the Content property, not a property of Content.
          // For example, changing the InnerXml or InnerText property of
          // Content will not be saved.
          contentEditor.Content = xmlElement;

          // persist changes to the database
          mgr.SaveChanges(contentEditor);
         }

        }
        catch (Exception ex)
        {
         //logLine("WebPart ERROR: " + ex.Message);
        }

       }
      }
     }
    }

   }

  }// end using
 }