SharePoint HealthReport - Missing Feature

Published on Monday, 16 October 2023

This is part of a series on SharePoint Health Report issues, because I can never remember what to do about them.

Posts in this series

Missing Feature

The warning looks like this:

Category        : MissingFeature
Error           : True
UpgradeBlocking : False
Message         : Database [WSS_Content] has reference(s) to a missing feature:
                  Id = [744b5fd3-3b09-4da6-9bd1-de18315b045d]. Feature (Id =
                  [744b5fd3-3b09-4da6-9bd1-de18315b045d]) is referenced in database
                  [WSS_Content], but isn't installed on the current farm. The missing
                  feature might cause upgrade to fail. If necessary, please install
                  any solution that contains the feature and restart upgrade.
Remedy          : Feature (Id = [744b5fd3-3b09-4da6-9bd1-de18315b045d]) is referenced in database [WSS_Content],
                  but isn't installed on the current farm. The missing feature might cause upgrade to fail. If
                  necessary, please install any solution that contains the feature and restart upgrade.

The solution here is either to install the missing feature - or remove the reference fully from the ContentDB.

Searching the internet results in many references to a script named Remove-SPFeatureFromContentDB to be used to remove the offending feature.

#Requires -PSSnapin Microsoft.SharePoint.PowerShell
<#
  .SYNOPSIS
	Remove Features from the contentDB
	adopted from https://gist.githubusercontent.com/wpsmith/ad57a1c78551be9c12b6/raw/92a99edaab517e48d06f5db19cff5033af034c13/Remove-Commandlets.ps1

  .EXAMPLE
	.\Remove-SPFeatureFromContentDB.ps1 -FeatureId 744b5fd3-3b09-4da6-9bd1-de18315b045d -ContentDb WSS_Content -WhatIf
	Reports on whether the feature 744b5fd3-3b09-4da6-9bd1-de18315b045d is used in any of the sites in WSS_Content
#>

[CmdletBinding(SupportsShouldProcess)]
param(
	[Parameter(Mandatory=$true)]
    [guid]$FeatureId,
	[Parameter(Mandatory=$true)]
    [string]$ContentDb
)

$ErrorActionPreference="Stop"

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-verbose "Feature ID specified does not exist in $($objName): $($obj.Url)"
    }
}


$db = Get-SPContentDatabase | where { $_.Name -eq $ContentDb }
[bool]$report = $false
if (!$PSCmdlet.ShouldProcess($FeatureId)) { $report = $true }

$db.Sites | ForEach-Object {
	$site = $_
	Remove-SPFeature -obj $site -objName "site collection" -featId $FeatureId -report $report
	Get-SPWeb -Site $site -Limit all | ForEach-Object {
		$web = $_
		Remove-SPFeature -obj $web -objName "site" -featId $FeatureId -report $report
	}

}