Test-SPContentDatabase : Automating missing feature removal
Recently I've been working with a customer to help them with a SharePoint migration project.
One of the steps that we've worked on is to run the Test-SPContentDatabase
cmdlet to check for missing files, features, web parts, assemblies, etc.
One of the content databases that was tested had somewhere in the region of 200 missing features. The customer confirmed that they didn't need to keep the feature references so we looked at ways of automating the removal of features (shockingly we never wanted to remove these manually!).
Test-SPContentDatabase return errors in a really nice format (Microsoft.SharePoint.Upgrade.SPContentDatabaseTestResult). As each error is returned as an object, we can check the 'Category' property in our script and do something if the category equals 'MissingFeature', which is what we do in the script. An example of the type of error that we want to check for:
[MissingFeature] Feature Id [fe5408f9-d9d4-a317-6c7f-122032c54475] is referenced [12] times in the database [WSS_Content_ContentDatabase1], but is not installed on the current farm.
We can check each error by storing all errors that are detected:
$testResults = Test-SPContentDatabase -Name -WebApplication
And then looping through each error individually:
foreach ($result in $testResults) { <# We want to check the type of error #> }
Once we've matched the category:
if ($result.Category -eq "MissingFeature") { <# We've found a missing feature #> }
We then extract the feature Guid from the 'message' property using a regular expression:
$regularExpression = "([a-f0-9]{8}[-][a-f0-9]{4}[-][a-f0-9]{4}[-][a-f0-9]{4}[-][a-f0-9]{12})" $match = [regex]::Matches($result.Message, $regularExpression) $guid = $match[0].Value
And then try to delete the feature reference by calling a function that we've created (see the entire script below):
Write-Host "Deleting feature id:" $guid Delete-SPFeatureReference -contentDatabase -guid $guid
Hopefully that all makes sense, the entire script is below:
$testResults = Test-SPContentDatabase -Name -WebApplication function Delete-SPFeatureReference() { Param ( [string]$contentDatabase, [string]$guid ) $db = Get-SPDatabase | Where-Object {$_.Name -eq $contentDatabase} foreach ($site in $db.Sites) { Start-SPAssignment -Global $siteFeature = $site.Features[$guid] if ($siteFeature) { $site.Features.Remove($siteFeature.DefinitionId, $true) } else { foreach ($web in $site.AllWebs) { $webFeature = $web.Features[$guid] if ($webFeature) { $web.Features.Remove($webFeature.DefinitionId, $true) } } } Stop-SPAssignment -Global } } foreach ($result in $testResults) { if ($result.Category -eq "MissingFeature") { $regularExpression = "([a-f0-9]{8}[-][a-f0-9]{4}[-][a-f0-9]{4}[-][a-f0-9]{4}[-][a-f0-9]{12})" $match = [regex]::Matches($result.Message, $regularExpression) $guid = $match[0].Value Write-Host "Deleting feature id:" $guid Delete-SPFeatureReference -contentDatabase -guid $guid } }
Hopefully this helps, you could extend the script to remove other kinds of errors based on the category.
Cheers,
Steve
Comments
- Anonymous
March 02, 2018
Nice post Steve, looks really good! Did your customer experience any issues after using this aproach?- Anonymous
March 06, 2018
Hi Christian,The customer never experienced any issues after removing the feature references.Cheers!Steve
- Anonymous