Fixing Uninstalled Activated Features

[Updated October 11 2008]

I uploaded a precompiled project with suitable visual studio project to google code (I’m fed up with wordpress file type restrictions by now), you can download the complete zip (includes wsp) here. Many thanks to Anthony Sumner for taking the time to create the package.

(Mine is sort of souped into a number of other stuff that I’m not at liberty of sharing freely)


In my former post on content deployment I had to cleanup old removed features before the content deployment would work. This post presents the tool that I build to fix those features.

The problem in a nutshell is that when a feature is activated (at some scope) and later uninstalled it still lingers in the content database. The feature doesn’t do much; it’s uninstalled, it doesn’t work, but it is still registered as being activated at that particular site, site collection, web application or farm. As far as I can see an uninstalled but activated feature only affects the affects the content deployment.

The procedure for finding where uninstalled features are activated is fairly straightforward:

  1. Go through every site collection and site recursively
  2. For each SPWebApp, SPSite and SPWeb
    1. Iterate through the *.Features collection
    2. For each feature, if the definition is null it is uninstalled but still activated

The way I’ve done it is to add a new webpage to the central administration site that will run through a given web application and list all the features activated at each level. It presents a “Remove” and “Remove (force)” next to each feature. Specifically all problematic features are listed at the very top of the page, so they can easily be removed (only forced removal work for these features) without looking through the entire list (it can be quite long).

I should probably stress that “remove” in this context simply means to deactivate the feature at the particular level.

It looks like this (with a couple of “bad” features):

Sorry for the beeps… 😉

Adding the Link to Central Admin

Add a feature with the following feature.xml file (shortened a bit as I have a lot more elements in it):

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns=""
Title="Carlsberg Administration Utilities"
Description="Adds a number of pages to the Utilities section on the Operations tab."
<ElementManifest Location="WebConfigModifications.xml" />
<!-- additional element manifest files for other features... -->

And “WebAppFeatureReporter.xml” file that will add a link to the webpage under the “Web Application Configuration” section on the Administration tab:

<Elements xmlns="">
Title="Web Application Features List" >
<UrlAction Url="/_admin/WebAppFeatureReporter.aspx"/>

Adding the Code

Finally we just need to add the actual code. There is only one file as I added the code directly to the aspx file, name it “WebAppFeatureReporter.aspx” and make sure that it’ll be copied to the /_admin folder under the template folder when the feature is deployed (your manifest.xml of the containing solution).

I’m satisfied with the functionality and layout of this page, but not the coding style within it. It was a rather quick hack that proved to work perfectly and stayed unchanged after that.

(note: If wordpress formatting messed something up – very likely – you can download the file here. Just rename file back to .aspx)

<%@ Assembly Name=”Microsoft.SharePoint.ApplicationPages, Version=,

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=,
Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase"
MasterPageFile="admin.master" %>
<%@ Import namespace="System.Reflection"%>
<%@ Import namespace="Microsoft.SharePoint.Administration"%>

<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>

<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint, Version=, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>

<%@ Register TagPrefix="wssuc" TagName="LinksTable" src="/_controltemplates/LinksTable.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection"
src="/_controltemplates/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl"
src="/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="LinkSection"
src="/_controltemplates/LinkSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection"
src="/_controltemplates/ButtonSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ActionBar"
src="/_controltemplates/ActionBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBar"
src="/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBarButton"
src="/_controltemplates/ToolBarButton.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="Welcome" src="/_controltemplates/Welcome.ascx" %>

<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"
Web application feature reporter
<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
<asp:Content ID="Content4" ContentPlaceHolderID="PlaceHolderAdditionalPageHead"
<asp:Content ID="Content5" ContentPlaceHolderID="PlaceHolderMain" runat="server">

<table width="100%">
<tr><td align="right">
<SharePoint:WebApplicationSelector id="selector" runat="server"

<asp:Literal ID="litMessage" runat="server" />
<asp:PlaceHolder ID="phMain" runat="server" />


<script runat="server" language="c#">

Hashtable parentObjects = new Hashtable();
string message = "";

protected override void OnLoad(EventArgs e)

protected override void OnPreRender(EventArgs e)

if (selector.CurrentItem == null)
message = "Please select a web application to modify";
litMessage.Text = "<span style='text-color:red;'>" + message + "</span>";

protected void OnContextChange(object sender, EventArgs e)
//Recreate the controls

protected override void CreateChildControls()

private void CreateControls()
//Rebuild controls

PlaceHolder pnlWebApp = new PlaceHolder();
PlaceHolder pnlSite = new PlaceHolder();
PlaceHolder pnlWeb = new PlaceHolder();
PlaceHolder pnlInvalid = new PlaceHolder();

SPWebApplication oApp = selector.CurrentItem;

if( oApp != null )
SPSecurity.RunWithElevatedPrivileges(delegate { ListFeatures(pnlWebApp,
pnlSite, pnlWeb, pnlInvalid, oApp); });

if (pnlInvalid.Controls.Count > 0)
AddHtml(phMain, GetHeaderByTitle("Invalid scope or installed \"missing\""
+ " feature definitions"));
AddHtml(phMain, "<TABLE cellpadding='2' cellspacing='2' width='100%'>");
AddHtml(phMain, "</TABLE>");


static void AddHtml(Control parent, string html)
LiteralControl lit = new LiteralControl();
lit.Text = html;

private void ListFeatures(
PlaceHolder pnlWebApplication,
PlaceHolder pnlSite,
PlaceHolder pnlWeb,
PlaceHolder pnlInvalid,
SPWebApplication webApp)

ListFeaturesAux("Web application", pnlWebApplication, pnlInvalid, webApp.Features);

foreach(SPSite site in webApp.Sites ){
ListFeaturesSite( pnlSite, pnlInvalid, site);
ListFeaturesWeb( pnlWeb, pnlInvalid, site.RootWeb );

private void ListFeaturesWeb(PlaceHolder pnlWeb, PlaceHolder pnlInvalid, SPWeb web)
ListFeaturesAux( "Web: " +  web.Url, pnlWeb, pnlInvalid, web.Features);

foreach( SPWeb subweb in web.Webs)
ListFeaturesWeb( pnlWeb, pnlInvalid, subweb);

private void ListFeaturesSite(PlaceHolder pnlSite, PlaceHolder pnlInvalid, SPSite site)
ListFeaturesAux( "Site collection: " +  site.Url, pnlSite, pnlInvalid, site.Features);

private void ListFeaturesAux(string header, PlaceHolder pnlContent,
PlaceHolder pnlInvalid, SPFeatureCollection features ){

AddHtml(pnlContent, GetHeader(header));
AddHtml(pnlContent, "<TABLE cellpadding='2' cellspacing='2' width='100%'>");

foreach (SPFeature feature in features)
if( feature.Definition != null )
//Feature Ok, add
GetRow(pnlContent, feature.Parent, feature.Definition);
AddHtml(pnlInvalid, "<tr><TD class='ms-vb2' style='font-weight: bold;'>");
AddHtml(pnlInvalid, "Missing feature definition (feature id:"
+ feature.DefinitionId + "), Scope: " + header );
AddHtml(pnlInvalid, "</td><td align='right'>");
AddUninstallButton(pnlInvalid, feature.Parent, feature.DefinitionId, false);
AddUninstallButton(pnlInvalid, feature.Parent, feature.DefinitionId, true);
AddHtml(pnlInvalid, "</td><tr>");

AddHtml(pnlContent, "</TABLE>");

protected static string GetHeader(string scope)
return GetHeaderByTitle("Features scoped at the level of the " + scope);

protected static string GetHeaderByTitle(string title)
StringBuilder sb = new StringBuilder();

sb.Append("<TABLE cellpadding='2' cellspacing='2' width='100%' class='ms-toolbar'>");
sb.Append("<TR><TD class='ms-toolbar' nowrap='true'>");
sb.Append("<TABLE cellpadding='1' cellspacing='0' border='0'><TR>");
sb.Append("<TD class='ms-toolbar' nowrap style='padding: 2px'>");
sb.Append( title + "</TD></TR></TABLE></TD></TR></TABLE>");

return sb.ToString();

protected void GetRow(PlaceHolder pnl, object parent, SPFeatureDefinition feature)

AddHtml( pnl, "<TR><TD class='ms-vb2' style='font-weight: bold;'>");
AddHtml( pnl, "<B>" + feature.DisplayName + "</B>  ("
+  feature.Id + ")</TD>");

AddHtml(pnl, "<TD align='right'>");
//Create uninstall buttons
AddUninstallButton(pnl, parent, feature.Id, false);
AddUninstallButton(pnl, parent, feature.Id, true);

AddHtml( pnl, "</TD></TR>");
AddHtml( pnl, "<TR><TD class='ms-vb2' colspan='2'><I>"
+ feature.GetDescription(new System.Globalization.CultureInfo("en-us"))
+ "</I></TD>");
AddHtml( pnl, "<TR><TD class='ms-vb2' colspan='2'>");

if( feature.ActivationDependencies.Count>0 ) {
AddHtml( pnl, "Activation dependencies:");
AddHtml(pnl, "<UL>");
foreach (SPFeatureDependency dep in feature.ActivationDependencies) {
SPFeatureDefinition depFet = GetFeature(dep.FeatureId);
AddHtml(pnl, "<LI>" + depFet.DisplayName + " (" + depFet.Id + ")</LI>");
AddHtml(pnl, "</UL>");
AddHtml(pnl, "</TD>");
AddHtml(pnl, "</TR>");

private void AddUninstallButton(PlaceHolder pnl, object parent, Guid featureId, bool force)
//Add the link to the parent object for this feature
string buttonId = GetFeatureContextId( parent, featureId );
parentObjects[ buttonId] = parent;

Button b = new Button();
b.ID = "remove_" + buttonId + "_" + force;
b.Text = "Remove" + (force ? " (force)" : "" );
b.CommandArgument = buttonId; //featureId.ToString();
b.CommandName = force ? "forceremove" : "remove";
b.Command += new CommandEventHandler(UninstallCommand);

pnl.Controls.Add( b );

/// <summary>
/// remove a given feature with or without force
/// </summary>
/// <param name="sender"></param>
/// <param name="e">CommandArgyment is the id of the feature, syntax: "parent name|feature guid"</param>
void UninstallCommand(object sender, CommandEventArgs e)
string operation = e.CommandName;
string globalFeatureId = e.CommandArgument.ToString();
Guid featureId = new Guid(globalFeatureId.Split('|')[1]);

//Should NEVER be null
object parent = parentObjects[globalFeatureId];

//Could have used reflection to invoke member, but this is more
// readable and less error prone.
SPFeatureCollection features;
if (parent is SPWebApplication)
features = ((SPWebApplication) parent).Features;
else if (parent is SPSite)
features = ((SPSite) parent).Features;
else if (parent is SPWeb)
features = ((SPWeb) parent).Features;
throw new ApplicationException("Unsupported parent:" + parent);

switch (operation)
case "remove":
message = "Removed feature:" + featureId;
case "forceremove":
message = "Removed feature:" + featureId + " (forced)";
features.Remove(featureId, true);
throw new ApplicationException(
"Failed to remove feature, unknown operation");

//Do a refresh (ok to do at this time
//  since only one command event will be fired per request)
catch( Exception exc )
message = exc.ToString();

/// Get a feature definition from the feature id
protected static SPFeatureDefinition GetFeature(Guid featureId)
SPFeatureDefinition retval = null;
foreach (SPFeatureDefinition feature in SPFarm.Local.FeatureDefinitions)
if (feature.Id == featureId)
retval = feature;
return retval;

/// Get a feature reference that includes the parent context.
/// Result is "parent id|feature id".
private static string GetFeatureContextId(object parent, Guid featureId)
if( parent is SPSite )
return ((SPSite)parent).ID + "|" + featureId.ToString("N");
else if( parent is SPWeb )
return ((SPWeb)parent).ID + "|" + featureId.ToString("N");
else if( parent is SPWebApplication)
return ((SPWebApplication)parent).Id + "|" + featureId.ToString("N");
throw new ApplicationException("Unknown feature parent:" + parent);

Final Comments

I will accept no critic of the actual code in the web page as it was compiled rather quickly by cut/paste from a few other custom admin pages, to solve a specific task as quickly as possible. I do like the way it’s added to the central administration site (thanks to Joel Oleson for that), it works, it looks fairly good, the code style is crap, let’s leave it at that 😉

I actually don’t remember where the original layout for this page came about but it was either something from Joels Oleson blog or a feature from GotDotNet or a mixture thereof.

The breadcrumb on the page is specified in another xml file, not shown here. See Joel’s blog for that subject, as it is not without problems and worth a proper discussion.

Hope it helps all of you guys to get an overview of where your features are used whether or not you use content deployment.

About Søren Nielsen
Long time SharePoint Consultant.

24 Responses to Fixing Uninstalled Activated Features

  1. Bob Davis says:

    THANK YOU for the excellent utility. I was losing what little hair I have left trying to get a content deploy working. This page let me find a feature the developer had activated at a subsite level then removed, preventing a successful deployment. Blew away the reference with this and all was well. THANK YOU SO MUCH.

  2. Slinger says:

    This looks like a fantastic solution. Unfortunately I think I am missing something, as I can’t get it to work.

  3. So what goes wrong for you? What error do you see?

    No link? (check xml files)
    No aspx/404? (check the filesystem to find where it was deployed, and if it matches your url)

    You should probably pay very close attention to the xml files and the way they are deployed. That is usually the culprit.

  4. Slinger says:

    After turning on custom errors, and I click the link I get the following error msg.

    The server block is not well formed. at System.Web.UI.TemplateParser.ProcessError(String message)
    at System.Web.UI.TemplateParser.DetectSpecialServerTagError(String text, Int32 textPos)
    at System.Web.UI.TemplateParser.ParseStringInternal(String text, Encoding fileEncoding)
    at System.Web.UI.TemplateParser.ParseString(String text, VirtualPath virtualPath, Encoding fileEncoding)

    If that’s any help.

  5. Sounds like one of the serverside tags are not well-formed. Try to re-copy the content of the aspx page.
    If that’s no help, you can try to verify that all tags are properly closed.

    The good news is that there don’t seem to be problems with the xml files.

  6. Pingback: What features are installed in your farm? « Slinger’s Thoughts

  7. I’ve now updated the post with a download link, so we can hopefully get around wordpress’ crappy formatting.

    I’ve used – and still do – the feature you refer to, however it only solves half the problem. Will post comments to your blog.

  8. Anthony says:

    Thanks so much!!

    I implemented it using Visual Studio 2008 and STSDEV util. Took a few tweaks in the xml files (my mistakes) and I’d fixed my problems in minutes thanks so much!

    Email me if you want the VS solution.

  9. LeoJ says:

    Hi Søren Nielsen,
    Thanks for this but i cannot get it to work..
    My Procedure like this,
    1. Create a WebAppFeatureReporter folder in \12\TEMPLATE\FEATURES\

    2. Craete a XML file call feature.xml and paste the your first xml code inside.

    3. Craete a XML file call WebConfigModifications.xml and paste your second code inside.

    4. Download the webappfeaturereporter.aspx file and then paste inside \12\TEMPLATE\FEATURES\_admin

    5. use stsadm -o InstallFeature -filename WebAppFeatureReporter\feature.xml -force

    6. Go Central Administration > Application Management > SharePoint Web Application Management > Web Application Features List

    Then I got error on page, do I did something not right?

    Thanks in advance!


  10. Hi LeoJ

    Sorry you didn’t get it to work immediately. There are many places you could have gone wrong.

    You didn’t write what the error was, so it’s hard to speculate. Hint: Disable custom errors and enable stacktrace in the web.config file for your central admin site.

    One guess: Have a look at the quotes in your file. I’ve sometimes seen them end up “mangled” when copied to/from the web/word.

    I’ve update the article with a link near the top. Have a look at that if you don’t want to spend any more time troubleshooting.

  11. LeoJ says:

    i use your .wsp and it works very nice. However i can’t find my broken feature… my feature is very easy, that is about some code in event handler to stop delete item… that is for testing code… but i uninstalled the feature which I didn’t deactivate.. so it is still working…(even I package my site to a .stp and deploy again..)…. so sad…

  12. LeoJ: Well the your feature is apparently uninstalled and everything looks dandy to SharePoint.

    As I understand it you did install an event handler (from a feature receiver?) and now the event handler is still running?

    If you are proficient in powershell it’s fairly easy to go and remove the event handler. If not then you should either
    1. Build a small program (10 lines) that unregisters your event at the right scope (site collection, site or list)

    2. Install some of the SharePoint manager programs that allows you to browse the object model. There are many and I can only remember af few:
    Echo made one (you need to register), “SharePoint manager”, “Sharepoint explorer”, “SharePoint inspector”.

    Search their feature sets to see which one will allow you to remove event handlers.

    Hope it helps.

  13. Ed says:

    I created a content deployment job on the source and configurede the target server to accept incoming request.

    After creating the job, I don’t see any option to Run the job.

    Where can I find it? Am I missing something?
    I had not problems when I created the job and tested the connection.


  14. John says:

    Wow. Amazing tool!

    I have installed it and it works great!

    BUT, i have found 2 duplicate features that I can not get rid of and it is not listed in the brokenfeaturelister!

    I believe it was installed/registered twice but with different guid id’s. Now I can’t activate either one! How do I get rid of them (i don’t have the guid id’s for them anymore)?

  15. Hi John

    Hmm I believe you can try to use:

    stsadm.exe -o uninstallfeature -name “your feature name” -force

    It should be enough with only the feature name and not id. It is for working features 😉

    If you still need the guid, you can try some of the SharePoint browser/manager tools, though they might have a hard time finding these features if my tool can’t.

    If that didn’t help:
    I also have another tool to list the features that are activated at some level but not installed anymore. I just haven’t gotten around to blog about it (and frankly forgot about it).
    Unfortunately it included in some larger admin package.
    What it does is described here go for the “Feature Problems” headline.

    Mail me if you really do need my aspx page. You will however need to clean it up quite a bit, don’t what will be the easiest path.
    My choice (if starting from scratch) would be powershell’ing it.

  16. John says:

    Thanks for the reply. I found that the problem lay in the fact that my dll was using a specific assembly key, but i would change my features unique id. WSS got confused… and showed multiple instances of it in that case. To fix this issue, I recompiled with a new assembly and new feature id and voila; everything works.

    I’m sure it is still in the content database though, so I will try using the 2nd tool you mentioned above.

    I really appreciate your help and now that I have found your blog will continue to follow it regularly!

  17. sara says:

    Nice !!!!!!!!

    Deleting Features from SharePoint.
    Try this too,

    Features From SharePoint

  18. says:

    great article, thanks for sharing.

  19. Pingback: Feature Uninstall « Sladescross's Blog

  20. Pingback: Automatic Fix of Pre Upgrade Issues (SharePoint 2007 to 2010) « Thoughts on computing, SharePoint and all the rest

  21. Rob Garrett says:

    Buddy, you saved my life with this tool – thanks a million

    • Hemant says:

      Hi Rob, Have you installed this Fixing Uninstalled Activated Features? how? This code is not working for me…

  22. Hemant says:

    I am getting error

    Object reference not set to an instance of an object. at ASP._admin_webappfeaturereporter_aspx.GetRow(PlaceHolder pnl, Object parent, SPFeatureDefinition feature)
    at ASP._admin_webappfeaturereporter_aspx.ListFeaturesAux(String header, PlaceHolder pnlContent, PlaceHolder pnlInvalid, SPFeatureCollection features)
    at ASP._admin_webappfeaturereporter_aspx.ListFeatures(PlaceHolder pnlWebApplication, PlaceHolder pnlSite, PlaceHolder pnlWeb, PlaceHolder pnlInvalid, SPWebApplication webApp)
    at ASP._admin_webappfeaturereporter_aspx.c__DisplayClass2.b__0()
    at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state)
    at Microsoft.SharePoint.SPSecurity.c__DisplayClass4.b__2()
    at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
    at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
    at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
    at ASP._admin_webappfeaturereporter_aspx.CreateControls()
    at ASP._admin_webappfeaturereporter_aspx.OnContextChange(Object sender, EventArgs e)
    at Microsoft.SharePoint.WebControls.ContextSelector`1.OnContextChange(EventArgs e)
    at Microsoft.SharePoint.WebControls.ContextSelector`1.set_CurrentId(String value)
    at Microsoft.SharePoint.WebControls.ContextSelector`1.OnLoad(EventArgs e)
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Control.LoadRecursive()
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: