Thursday, September 17, 2009

Dealing with abducted SharePoint features

If you've ever gotten an error message when deploying a feature with stsadm or WSPBuilder, resembling the following:

The feature '...' uses the directory "NewFeatureName" in the solution. However, it is currently installed in the farm to the directory "OldFeatureName". Uninstall the existing feature before you install a new version of the solution.
... or you've loaded up SharePoint Manager 2007, checked the feature definitions, only to find one or more features without the green "ALL IS OK" icon, an error reading "Object reference not set to an instance of an object" when you try to open them, and no option to delete.

... or you've otherwise been slapped a message indicating that you've once had a feature installed somewhere, but although its files are now gone, SharePoint won't allow you to deploy a new one with the same guid.

The solution is relatively simple, and can be automated with a lookup of the local farm's feature definitions, deleting those who throw an "not found" error when you attempt to access its properties. Kind as I am, I've already thrown this together for you, and made it available as a download here (Grep.SharePoint.Tools.CleanFeatures). The source code follows below:

namespace Grep.SharePoint.Tools.CleanFeatures
{
using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

internal class Program
{
private static void Main(string[] args)
{
if (!args.Contains("/D"))
{
Console.Out.WriteLine("Listing missing features. Invoke with /D to delete as they are found.");
}
else
{
Console.Out.WriteLine("Deleting missing features.");
}

SPFarm farm = SPFarm.Local;
foreach (SPFeatureDefinition feature in farm.FeatureDefinitions)
{
try
{
SPFeaturePropertyCollection p = feature.Properties;
}
catch (SPException e)
{
if (e.ErrorCode == -2146232832)
{
Console.Out.WriteLine("Not found: {0} ({1})",
feature.Id,
feature.RootDirectory.Substring(feature.RootDirectory.LastIndexOf(@"\") + 1));
if (args.Contains("/D"))
{
feature.Delete();
}
}
}
}
Console.Out.WriteLine("Done");
}
}
}

0 comments: