2017-11-29 22:23:14

SharePoint Missing Setup Files Webparts

As like from my last post covers any missing features, that won't actually remove any webparts the third party application installed along the way.
So here;s the next solution should you need to remove those web parts, if you don't wish to re-install the third party solution.

EXample Error Message:

Category        : MissingSetupFile
Error           : True
UpgradeBlocking : False
Message         : File [Features\SourceCode.SharePoint.WebPart.Reporting14_ReportingWebparts\ActivityGraph\ActivityGraph.webpart] is 
                  referenced [1] times in the database [WSS_Content_OpsCentre], but is not installed on the current farm. Please install 
                  any feature/solution which contains this file.
Remedy          : One or more setup files are referenced in the database [WSS_Content_OpsCentre], but are not installed on the current 
                  farm. Please install any feature or solution which contains these files.
Here's my script, just as effective and vulgur as my last one. :D
Solution:
########################################################################################################################## 
# Author: Zewwy (Aemilianus Kehler)
# Date:   Oct 28, 2017
# Script: Delete-SPWebParts
# This script allows to remove Web Parts from the Web Parts Gallery.
# Cudos to Carlos from Technet Galleries  
# Required parameters: 
#   A valid root SharePoint Web URL and a case senstive string for the particular Web Part.
#   Best to be run from a SharePoint Mgmt Console with an account that has collection admin on the Web URL 
##########################################################################################################################

##########################################################################################################################
#   Variables
##########################################################################################################################

#The Variable used to display the message that no web parts were found.
$NoWPFound = "Sorry to inform you, but the system returned no results for deletion. :("

#The Varible used to display wrong URL provided, or not found
$BadURL = "Sorry doofus that is not a known SharePoint Web URL"

#MyLogoArray
$MylogoArray = @("#####################################","# This script is brought to you by: #","#                                   #","#             Zewwy                 #","#                                   #","#####################################"," ")

#Static Variables
$pswheight = (get-host).UI.RawUI.MaxWindowSize.Height
$pswwidth = (get-host).UI.RawUI.MaxWindowSize.Width

##########################################################################################################################
#   Modules
##########################################################################################################################

#Load Sharepoint Modules
If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )  
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell }


##########################################################################################################################
#   Functions
##########################################################################################################################

#function takes in a name to alert confirmation of deletion of a web part, returns true or false
function confirm($name)
{
    #function variables, generally only the first two need changing
    $title = "Confirm WebPart Deletion!"
    $message = "You are about to delete WebPart: $name"

    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "This means Yes"
    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "This means No"

    $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

    $result = $host.ui.PromptForChoice($title, $message, $Options, 0)

    Switch ($result)
        {
              0 { Return $true }
              1 { Return $false }
        }
}

#Function provided by phil to check the content database via the sharepoint front end server
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 that delete Web Parts from the Web Parts catalog 
function RemoveWebPartsFromCatalog ($SPWA, $TSFWP)
{    
    try 
    {    
        #Variable to hold the Web Part Catalog, I'm not sure exactly why this line is here       
        $wpCatlog = [Microsoft.SharePoint.SPListTemplateType]::WebPartCatalog
        #This on creates a variable to hold the list of all the web parts located in the catalog
        $WPList = $SPWA.GetCatalog([Microsoft.SharePoint.SPListTemplateType]::WebPartCatalog)
        #Orginally i attmpted to delete the web part directly in the inital foreach loop
        #However since the item wanting to be deleted is part of the system array variable we are iterating through
        #It would crash the script after deleting the first item asked to successfully, instead
        #theres a variable used to contain all the web part ids to run a second foreach loop
        $wpIDlist = @()      
        foreach ($spItem in $WPList.Items)  #Iterating through all web parts
        {
            $S1=$TSFWP.ToLower();$S2=$spItem.DisplayName.ToLower(); # To deal  with case sensitivity   
            if($S2.Contains("$S1")) #Check for given string (this is the case senstive bullshit part)
            {  
               # $wpName = $spItem.DisplayName
               # Centeralize "Web Part Found!: $wpName" "yellow"
               # Write-Host "Web Part ID!: " $spItem.ID
                $wpIDlist += $spItem.ID 
            }                                   
        }
        #if No Web Part Found 
        if($wpIDlist.Count -eq 0)
        {
            Centeralize $NoWPFound "yellow"
        }
        else
        {
            foreach($wp in $wpIDlist)
            {
                $wpItem = $WPList.GetItemById($wp)
                $wpName = $wpItem.DisplayName
                Centeralize "Web Part Found!: $wpName" "yellow" 
                if (confirm $wpItem.DisplayName)
                {
                    Centeralize "Deleting Web Part: $wpName`n" "Red"
                    $wpItem.Delete() 
                } 
            }
            $WPList.Update()
        }     
        $WPList.Update() 
        $SPWA.Dispose()     
    } 
    catch [System.Exception] 
    { 
        write-host -f red $_.Exception.ToString() 
    } 
}

#Function to Centeralize Write-Host Output, Just take string variable parameter and pads it
#Nerd Level over 9000!!! Ad-hoc Polymorphic power time!!
function Centeralize()
{
  param(
  [Parameter(Position=0,Mandatory=$true)]
  [string]$S,
  [Parameter(Position=1,Mandatory=$false,ParameterSetName="color")]
  [string]$C
  )
    $sLength = $S.Length
    $padamt =  "{0:N0}" -f (($pswwidth-$sLength)/2)
    $PadNum = $padamt/1 + $sLength #the divide by one is a quick dirty trick to covert string to int
    $CS = $S.PadLeft($PadNum," ").PadRight($PadNum," ") #Pad that shit
    if ($C) #if variable for color exists run below
    {    
        Write-Host $CS -ForegroundColor $C #write that shit to host with color
    }
    else #need this to prevent output twice if color is provided
    {
        $CS #write that shit without color
    }
}

#Start actual script by posting and asking user for responses
foreach($L in $MylogoArray){Centeralize $L "green"}
Centeralize "Delete-SPWebParts; cause some Web Parts just suck ass.`n" "White"
#Notify User to enter the Site Collection URL then check if it exits.
Centeralize "Please enter a SP Web URL`n"
Write-host "SharePoint Web URL: " -ForegroundColor Magenta -NoNewline
$SPWebURL = Read-Host
Write-Host " "
Centeralize "Verifying SharePoint web URL, Please Wait...`n"
if ($SPWeb=Get-SPWeb $SPWebURL -EA SilentlyContinue)
{
    Centeralize "K, The SPWeb URL you entered appears to be valid.`n" "Cyan"
    if(!$SPWeb.IsRootWeb){Centeralize "But it is not a root web, you fail!" "Red"; Exit}
    Write-Host "Sigh... This HAS to be case sensitive.`nNow what does the Web Part name you are looking for contain? " -ForegroundColor Magenta -NoNewline
    $SPWPS = Read-Host
    #Write-Host " " #Need this to make new line
    #if(Confirm "$SPWPS from: $SPWebURL")
    #{
        $Ugh = @(" ","Attempting to locate web parts with the parameters you defined.","Please Wait.","I must say you are not making this easy."," ")
        foreach($lineitem in $Ugh){Centeralize $lineitem "Cyan"}
        RemoveWebPartsFromCatalog $SPWeb $SPWPS
    #}
}
else
{
    Centeralize $BadURL "red"
}

Posted by Aemilianus Kehler | Permanent link