Wednesday, 1 June 2011

Removing features from a content database in SharePoint 2010 using PowerShell

The great thing about the Health Analyzer in SharePoint 2010 is that it will report on a number of potential issues with the server farm, which may cause a problem later whilst applying a cumulative update or service pack. Resolving these issues in advance will help to prevent an update failing when you run the SharePoint Configuration Wizard.

One of these problems may occur when a solution is removed from the farm before the corresponding features were deactivated from site collections and sites. The Health Analyzer will place this issue in the “Configuration” category with the title “Missing server side dependencies”.

Missing server side dependencies

The error message reported will look similar to this one:

[MissingFeature] Database [SharePoint_Content_Portal] has reference(s) to a missing feature: Id = [8096285f-1463-42c7-82b7-f745e5bacf29], Name = [My Feature], Description = [], Install Location = [Test-MyFeature]. The feature with Id 8096285f-1463-42c7-82b7-f745e5bacf29 is referenced in the database [SharePoint_Content_Portal], but is not installed on the current farm. The missing feature may cause upgrade to fail. Please install any solution which contains the feature and restart upgrade if necessary.

As shown above, this message reports a content database name (SharePoint_Content_Portal) and feature ID (8096285f-1463-42c7-82b7-f745e5bacf29), but not the sites or site collections where the feature exists. In addition to this, even if you did know where the feature was activated, it will not appear anywhere in the UI for you to deactivate because the solution has been removed from the farm.

The following PowerShell script will interrogate a specified content database and feature ID and do two things:

  1. Produce a report in the PowerShell console showing which sites or site collections contain the offending feature.
  2. Forcibly deactivate the feature from the applicable sites or site collections.

Note: Whilst this article applies specifically to the scenario of deactivating features from removed solutions reported by the Health Analyzer, I have decided to write the script so that it deactivates any specified feature from sites and site collections – not just those missing from the farm. This allows the script to be used in other scenarios, too.

To use the script, run these functions in a PowerShell console with the SharePoint 2010 add-ons loaded:

function Remove-SPFeatureFromContentDB($ContentDb, $FeatureId, [switch]$ReportOnly)
{
    $db = Get-SPDatabase | where { $_.Name -eq $ContentDb }
    [bool]$report = $false
    if ($ReportOnly) { $report = $true }
   
    $db.Sites | ForEach-Object {
       
        Remove-SPFeature -obj $_ -objName "site collection" -featId $FeatureId -report $report
               
        $_ | Get-SPWeb -Limit all | ForEach-Object {
           
            Remove-SPFeature -obj $_ -objName "site" -featId $FeatureId -report $report
        }
    }
}

function Remove-SPFeature($obj, $objName, $featId, [bool]$report)
{
    $feature = $obj.Features[$featId]
   
    if ($feature -ne $null) {
        if ($report) {
            write-host "Feature found in" $objName ":" $obj.Url -foregroundcolor Red
        }
        else
        {
            try {
                $obj.Features.Remove($feature.DefinitionId, $true)
                write-host "Feature successfully removed from" $objName ":" $obj.Url -foregroundcolor Red
            }
            catch {
                write-host "There has been an error trying to remove the feature:" $_
            }
        }
    }
    else {
        #write-host "Feature ID specified does not exist in" $objName ":" $obj.Url
    }
}

You now have two options for using these functions. If you just want to produce a report in the console showing which sites and site collections contain the feature, type the following (note the ReportOnly switch on the end):

Remove-SPFeatureFromContentDB -ContentDB "SharePoint_Content_Portal" -FeatureId "8096285f-1463-42c7-82b7-f745e5bacf29" –ReportOnly

This command will step through all sites and site collections and display the following message whenever it finds the feature specified:

Feature found in site : http://portal/site

If you want to go ahead and remove the feature from all sites and site collections in the content database, type the same command without the ReportOnly switch on the end:

Remove-SPFeatureFromContentDB -ContentDB "SharePoint_Content_Portal" -FeatureId "8096285f-1463-42c7-82b7-f745e5bacf29"

Running this command will step through all sites and site collections, remove the feature specified, and display the following output:

Feature successfully removed from site : http://portal/site

You should now be able to reanalyse the “Missing server side dependencies” issue in the Health Analyzer to clear the problem (providing there are no other issues reported under that title, of course!).

Note: If you found this article looking for information on how to diagnose MissingSetupFile issues in the SharePoint Health Analyzer, rather than the MissingFeature issue, then have a look at my follow up article. For information on troubleshooting MissingWebPart and MissingAssembly errors, take a look at this article.

50 comments:

  1. Andrew Marvin4 August 2011 11:39

    Thanks for this Phil,

    I came across this problem on an upgraded farm and tried running this solution. However I get a permissions error despite running it as an account that is Farm Administrator and had access to the SQL DB.

    Has anyone else came across this and managed to resolve?

    ReplyDelete
    Replies
    1. I had the same problem, I added myself as an administrator to the Site Collection and it fixed the issue.

      Delete
    2. I have also had this problem. Including the instance with the db server fixed it for us (dbserver\instance).

      Delete
  2. This script worked great. I got this error after doing a site collection backup and then doing a site collection restore on another server/instance. Obviously there were some difference between the two because I got many "Missing Feature" errors. After running this for each of the items/references identified the "Server side dependencies" error went away.

    ReplyDelete
  3. Andre, I have seen this in situations when the account you are using as a Farm Administrator does not have "Execute" permission on the content database or Config database, Forget which one is needed. Don't know for sure if that's the cause of this, but it seems quite similar to what I have experienced.

    ReplyDelete
  4. I am getting an error that remove-spfeature is not a valid cmdlet. However, I am using the SP Admin Shell, with all the snap-ins already installed.

    Has anyone else seen this issue?

    ReplyDelete
  5. Hi. I also saw this issue using SP Admin Shell, however if you use Windows Shell with the SP snap-in, it does work. Although i did get Access denied errors, bizarely it did still remove the offending feature, and the missing server side dependancies error message went away. Which in my eyes is result! Thanks for this blog.

    ReplyDelete
  6. PowerShell:
    The term 'Remove-SPFeatureFromContentDB' is not recognized as the name of a cmdlet, function, script file, or operable program.

    Any idea? I run the shell by farm admin as run as administrator...
    Marian

    ReplyDelete
  7. Thanks! Helped me alot!

    /Andreas

    ReplyDelete
  8. Works perfectly!

    But, when the site is already deleted it doesn't work.

    Doe you have a solution for that one?

    ReplyDelete
  9. Worked great! For those of you getting cmdlet errors, You cannot run the Remove-SPFeatureFromCOntentDB until after you have successfully loaded the entire script at the beginning of the article. That long script creates the "Remove-SPFeatureFromCOntentDB" cmdlet

    ReplyDelete
  10. so great
    Thanks alot!.
    /KL

    ReplyDelete
  11. Thanks, thanks, and more thanks for sharing this great bit of knowledge. It worked like a charm for my problem.

    ReplyDelete
  12. getting error "Get-SPWeb : Syntax Error: Either provide a full Url or an SPSite object". please help.

    ReplyDelete
  13. One missing from this article that took a little while to troubleshoot as I am new to PowerShell, but I got it to work... add either of the Remove commands directly at the bootom of the script depending on which you want to use. I was making the mistake of saving the script, running it, and then attempting to run the "Remove" commands which yielded a "RemoveFeaturefromContentDB not found" error. After adding it directly to the script, it worked perfectly.

    ReplyDelete
    Replies
    1. I continue receiving the error "RemoveFeaturefromContentDB not found" What the step by step?
      I save the long script as .ps1, after try use copy/paste on powershell and the result was the same.

      Delete
  14. I´m getting 'Remove-SPFeatureFromContentDB' is not recognized, I saved the first and long script as .ps1 and have executed on sharepoint PS. but I continue with the same message. Please I need a lot this, can someone pass the step by step to this work?
    thank you

    ReplyDelete
    Replies
    1. I got it working by following steps:
      1) Run Powershell via User who has access to the contentdb
      2) Copy and paste those script in powershell - it should load without any problems
      3) Run the commands below the script with your own ContenDB name and feature id: Remove-SPFeatureFromContentDB -ContentDB "YOUR_CONTENT_DB_HERE" -FeatureId "YOUR_FEATURE_ID_HERE"

      Delete
    2. You have to run the script using the following syntax
      "PS C:\Windows\System32> . "FullPath to Script\Script.ps1"

      Delete
  15. I am not sure what I am doing wrong with this. I am new to powershell, so be kind. I get the script to run but I get a "cannot index into a null array." referencing the $featId in the second function. I am not sure what this error means or how to fix it. If someone has any info please let me know. -john

    ReplyDelete
    Replies
    1. Never mind I figured this one out. Thanks for the script!
      -john

      Delete
  16. what did you figure out? I get the same "null array" messages.

    ReplyDelete
    Replies
    1. Most likely one of the parameters you passed, is not correct. Check the names.

      You rock Phil (yet AGAIN)!

      Delete
  17. I M FACING THIS error please help me out ------The term 'remove' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.-----

    ReplyDelete
  18. I am facing this issue as well. I noticed that I can not see the database. is it because the account i am using is not showing as the owner of the database?

    ReplyDelete
  19. Thanks very much for this - I am using the scripts to prepare for upgrading to 2013.
    I still have some issues but can't figure out the answer. I have identified the faulty directory name (eg, reports\kpis). However, some time ago I created a new site collection with a new contentdb for these pages and recreated them in the new collection. The old collection was deleted but the test-spcontentdatabase command still reports them as missing. Any ideas?

    ReplyDelete
  20. This was very helpful. Thanks so much!

    ReplyDelete
  21. This script worked great. Thanks so much for posting.

    ReplyDelete
  22. The term 'Remove-SPFeatureFromContentDB' is not recognized as the name of a cmdlet... I continue to have this error on production server instead, on my lab environment not... any idea why?

    Fabio

    ReplyDelete
  23. I have question, how much time for you was installing above functions?

    Best regards,

    ReplyDelete
  24. Great Job. This script worked great. Thanks so for posting.
    Mani Subramanian

    ReplyDelete
  25. I have loaded the function in Powershell and executed the command also but i didnt receive any output.

    but missing features errors are still reflecting in the Health Analyzer so missing features are there but i am not able able to get the list of site collection where we have these missing features.

    can somebody pls advice

    ReplyDelete
  26. I am having the same problem - when I enter the initial script, that appears to work and then when I enter the Remove-SPFeatureFromContentDB... command, it just goes back to the cursor - no output.

    ReplyDelete
    Replies
    1. Kelly - I am getting this too, did you find a fix for this particualr problem?

      Cheers.

      Delete
    2. I have the same issue! Any idea?

      Delete
    3. I found out that the main function receive nulls even when I am sending them. I am stuck on this. Please any light in the dark?

      Delete
  27. The BEST script EVER!!! Worked perfectly. Thank you.

    ReplyDelete
  28. Worked like a charm.
    Thanks a million for sharing.

    ReplyDelete
  29. Any idea how to re-work this for SP 2013? The $db object doesn't have a Sites object and the following errors are thrown.

    Cannot index into a null array.
    At line:22 char:9
    + $feature = $obj.Features[$featId]
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

    Get-SPWeb : Syntax Error: Either provide a full Url or an SPSite object.
    At line:13 char:18
    + $_ | Get-SPWeb -Limit all | ForEach-Object {
    + ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (Microsoft.Share....SPCmdletGetWeb:SPCmdletGetWeb) [Get-SPWeb], SPCmdletPipeB
    indException
    + FullyQualifiedErrorId : Microsoft.SharePoint.PowerShell.SPCmdletGetWeb

    ReplyDelete
  30. Frustrating. I played around with the command line. Had to get the DB by ID before it would treat it as an object. I can get the sites but the pipeline doesn't want to accept the allwebs.

    Hoping u come up with a workable solution. Didn't want to re-import the DB from 2010 again but may have to.

    ReplyDelete
  31. How do you run the functions in the SP Management Shell?

    ReplyDelete
  32. This doesn't seem to work with WebParts, only features. Can you post a modified version of this script for WebParts?

    Thank you in advance

    ReplyDelete
  33. This comment has been removed by the author.

    ReplyDelete
  34. # Hunt orphaned files
    # Set $TargetDB to name of
    # Set Features to an array containing all the troublesome Feature IDs seperated

    $TargetDB= ""
    $Features = ('FeatureID1','FeatureID2')

    function Remove-SPFeatureFromContentDB($ContentDb, $FeatureId, [switch]$ReportOnly)
    {
    (as original)
    }

    function Remove-SPFeature($obj, $objName, $featId, [bool]$report)
    {
    (as original)
    }


    foreach ($FeatureID in $Features) {

    $SpitItOut = "Now looking for Feature: " + "$FeatureID"
    write-Host $SpitItOut
    write-Host "`n"
    # Pick one line from below
    # with or without -reportonly
    # Remove-SPFeatureFromContentDB -ContentDB $TargetDB -FeatureId $FeatureID –ReportOnly
    Remove-SPFeatureFromContentDB -ContentDB $TargetDB -FeatureId $FeatureID

    write-Host "That's it, next one.." -foregroundcolor Green
    write-Host "`n"
    }

    ReplyDelete
  35. ^^Nice post - thanks for sharing!

    ReplyDelete
  36. Thanks for the post . I could remove all the missing features except one i.e
    Database has reference(s) to a missing feature: Id = [525dc00c-0745-47c0-8073-221c2ec22f0f], Name = [Project Workspace Document Libraries], Description = [Provides support for Microsoft Office Project Server document libraries.], Install Location = [pwsdoclibs].
    I tried REmove-SpFeatureFromContentDB -ReportOnly but it does not return any website . I went ahead and deleted the feature . Then when i run Test-spcontentDatabase the missing feature still shows up. Is there a way to remove it permanantly?

    ReplyDelete
  37. Extremely useful post, Phil...helped me past my SharePoint 2010 SP2 installation woes. Thanks for sharing.

    ReplyDelete
  38. Hi Phil,

    I'm COMPLETELY new when it comes to using Powershell and any kind of scripting but I'm having this exact issue after restoring some production databases to our test environment. I tried running the first script in the Sharepoint 2010 Management Shell but nothing happens. I saved your script as a .ps1 file and used to following command to run it:
    &"D:\Scripts\test.ps1" and then hit 'enter'. Nothing happens...

    THanks,

    Andre

    ReplyDelete
  39. How do I save the file with the functions and run it?

    ReplyDelete
  40. If somebody has this Error:
    "Get-SPWeb : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" despite having site collection admin permissions, one should call Remove-SPFeatureFromContentDB like this:
    [Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges({
    Remove-SPFeatureFromContentDB -ContentDB "InfobipSPDEV_PortalHome_Content" -FeatureId "5b2bb397-0d2b-4faa-8e8c-fb6cf8555006" –ReportOnly
    });

    ReplyDelete