In certain scenarios Web Part references can get orphaned in the Content DB’s.

The Symptoms

In that same health analyzer report about “Missing server side dependencies” in Central Admin that reports MissingFeatures and MissingAssemblies, you will also sometimes find MissingWebPart errors:

image001

[MissingWebPart] WebPart class [0a61962f-1566-0eb7-5b6f-dede51497848] (class [AEBlogRollupWebpart.AEBlogRollup] from assembly [AEBlogRollupWebpart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8d6c92310d8d661d]) is referenced [3] times in the database [sp_GoContent1], but is not installed on the current farm. Please install any feature/solution which contains this web part. One or more web parts are referenced in the database [sp_GoContent1], but are not installed on the current farm. Please install any feature or solution which contains these web parts.

[MissingWebPart] WebPart class [28c23aec-2537-68b3-43b6-845b13cea19f] is referenced [3] times in the database [sp_GoContent4], but is not installed on the current farm. Please install any feature/solution which contains this web part. One or more web parts are referenced in the database [sp_GoContent4], but are not installed on the current farm. Please install any feature or solution which contains these web parts.
[MissingWebPart] WebPart class [28c23aec-2537-68b3-43b6-845b13cea19f] is referenced [2] times in the database [sp_AdminContentDB], but is not installed on the current farm. Please install any feature/solution which contains this web part. One or more web parts are referenced in the database [sp_AdminContentDB], but are not installed on the current farm. Please install any feature or solution which contains these web parts.

The Cause

These events are logged because the migrated SharePoint 2010 Sites contains some references to custom WebPart files and the linked feature/solution are not installed in the Farm.

The Fix

How does one clean this crap up? Easy, dress up a kid in this ridiculous outfit and parachute them into your SharePoint portal:

imagesCA1J0UT9
The easy solution is obviously to have the baby mop install the features/solution related to those webpart , but if you are in the same situation as us, you don’t really need the webpart anymore and you just want the database to be clean and get rid of these events.
To safely remove the webparts and references, we need to be able to identify their specific location on the Farm.

1. Create the following script as a .ps1 PowerShell (text) file:

param (
    [string]$DBserver = $(throw "Missing server name (please use -dbserver [dbserver])"),
    [string]$path = $(throw "Missing input file (please use -path [pathfile.txt])")
)

#Set Variables
$input = @(Get-Content $path)

#Addin SharePoint2010 PowerShell Snapin
Add-PSSnapin -Name Microsoft.SharePoint.PowerShell

#Declare Log File
Function StartTracing
{
    $LogTime = Get-Date -Format yyyy-MM-dd_h-mm
    $script:LogFile = "MissingWebPartOutput-$LogTime.csv"
    Start-Transcript -Path $LogFile -Force
}

#Declare SQL Query function
function Run-SQLQuery ($SqlServer, $SqlDatabase, $SqlQuery)
{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server =" + $SqlServer + "; Database =" + $SqlDatabase + "; Integrated Security = True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
}

function GetWebPartDetails ($wpid, $DBname)
    {
    #Define SQL Query and set in Variable
    $Query =  "SELECT * from AllDocs inner join AllWebParts on AllDocs.Id = AllWebParts.tp_PageUrlID where AllWebParts.tp_WebPartTypeID = '"+$wpid+"'"

    #Runing SQL Query to get information about Assembly (looking in EventReceiver Table) and store it in a Table
    $QueryReturn = @(Run-SQLQuery -SqlServer $DBserver -SqlDatabase $DBname -SqlQuery $Query | select Id, SiteId, DirName, LeafName, WebId, ListId, tp_ZoneID, tp_DisplayName)

    #Actions for each element in the table returned
        foreach ($event in $QueryReturn)
        {
            if ($event.id -ne $null)
                {
                #Get Site URL
                $site = Get-SPSite -Limit all | where {$_.Id -eq $event.SiteId}

                #Log information to Host
                Write-Host $wpid -nonewline -foregroundcolor yellow
                write-host ";" -nonewline
                write-host $site.Url -nonewline -foregroundcolor green
                write-host "/" -nonewline -foregroundcolor green
                write-host $event.LeafName -foregroundcolor green -nonewline
                write-host ";" -nonewline
                write-host $site.Url -nonewline -foregroundcolor gray
                write-host "/" -nonewline -foregroundcolor gray
                write-host $event.DirName -foregroundcolor gray -nonewline
                write-host "/" -nonewline -foregroundcolor gray
                write-host $event.LeafName -foregroundcolor gray -nonewline
                write-host "?contents=1" -foregroundcolor gray -nonewline
                write-host ";" -nonewline
                write-host $event.tp_ZoneID -foregroundcolor cyan
                }
         }
    }

#Start Logging
StartTracing

#Log the CVS Column Title Line
write-host "WebPartID;PageUrl;MaintenanceUrl;WpZoneID" -foregroundcolor Red

foreach ($event in $input)
    {
    $wpid = $event.split(";")[0]
    $DBname = $event.split(";")[1]
    GetWebPartDetails $wpid $dbname
    }

#Stop Logging
Stop-Transcript

2. Paste the above code in a PowerShellScript file, like [MissingWebPartDetails.ps1] and copy it on your local SharePoint Server Drive.
Launch the script from a Windows Powershell Cmd Prompt using the following parametters:

.MissingWebPartDetails.ps1 -DBserver <SQLServerName> -path <fullpathmissingwebparts.txt>

[pathmissingwebparts.txt] is a input file you need to create based on the [MissingWebPart] errors that you get on the SharePoint Health Analyzer
The input.txt file should be formated like this (WebPartId;ContentDatabase), example:

36f2680f-4855-f100-da5b-5dd1d07ae62b;sp_GoContent1
d0d5a8f7-2e30-7cd0-276e-7cdc1aac9ab8;sp_GoContent1
7dac9698-9043-eb31-b853-be8c1705512b;sp_GoContent1
150b4681-ae25-d7be-bc71-1410062c7315;sp_GoContent1 60085034-7d97-27c7-5823-2f941e6be1de;sp_GoContent1 7a95935f-d524-5992-f505-809725b6a9e2;sp_GoContent1
710dd8b1-df44-baec-3f85-84ef85658f95;sp_GoContent1

After execution, the script generates a CSV output file in the same folder with details about the webpart location (PageUrl / MaintenanceUrl / Webpart Zone ID).
In our case, the outputs looked something like this:

Transcript started output file is MissingWebPartOutput-2013-03-19_9-17.csv
WebPartID;PageUrl;MaintenanceUrl;WpZoneID
0a61962f-1566-0eb7-5b6f-dede51497848;https://MySharepoint.com/default.aspx;https://MySharepoint.com/Pages/default.aspx?contents=1;MainZone
0a61962f-1566-0eb7-5b6f-dede51497848;https://MySharepoint.com/default.aspx;https://MySharepoint.com/Pages/default.aspx?contents=1;MainZone
0a61962f-1566-0eb7-5b6f-dede51497848;https://MySharepoint.com/default.aspx;https://MySharepoint.com/Pages/default.aspx?contents=1;MainZone
28c23aec-2537-68b3-43b6-845b13cea19f;/home.aspx;/NintexWorkflowReportPages/home.aspx?contents=1;FullPage
28c23aec-2537-68b3-43b6-845b13cea19f;/home.aspx;/NintexWorkflowReportPages/home.aspx?contents=1;FullPage
**********************
Windows PowerShell transcript end
End time: 20130319091716
**********************

Looking at the URL’s in here, we can see that the offending Web Parts are on the page (or, in our case, old document versions of the pages) https://MySharepoint.com/default.aspx and the second web part, a little trickier but clear if you think about it a bit, is located on the Central Administration web app: /NintexWorkflowReportPages/home.aspx. For page #1, going into the Pages library in SharePoint and deleting (after checking with your team of course) the old versions of the page is the first step.

2
For page #2, going to the offending page in Central Admin and deleting the broken web parts visible on the live page does the trick. But wait, there’s more! We need to also clear ALL recycle bins in SharePoint, at all levels. This calls for the secret weapon:
imagesCA25SZL6
For each web application in question, modify the following PowerShell and execute:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$WebApp=get-spwebapplication "https://MySharepoint.com"
    foreach ($SPSite in $webApp.Sites)
    {
     #get the collection of webs
      foreach($SPWeb in $SPSite.AllWebs)
         {
             #Empty the 1st Stage Recycle bin items PERMENANTLY
             #$SPWeb.RecycleBin.DeleteAll();
             #Send the 1st Stage Recycle bin items to 2nd Stage
             $SPWeb.RecycleBin.MoveAllToSecondStage();
              write-host "End-User Recycle Bin Items Deleted for:"
              write-host $SPWeb.title ":" $SPWeb.URL "`n"
         }
             #Empty SharePoint site collection recycle bin (Second Stage Recycle bin) or Admin Recycle bin
             $SPSite.RecycleBin.DeleteAll();
  write-host "Administrator Recycle bin Items Deleted for:" $SPSite.RootWeb.title "`n"
    }

After all this is done, you should now be able to go back to the Health Analyzer and click Re-analyze, and the errors should go away. Great job, baby mops!

Thanks to Etienne for the main script – hopefully I have helped someone out by rejigging it with all the additional followup bits required.

Note: To remove the [MissingFeature] Database errors, check out this BLOG post.

To remove the [MissingWebPart] WebPart class errors, check out this BLOG post.