SharePoint Closed WebParts Slowing You Down? Migrating from SharePoint 2007 to 2010 and Can't Find an Easy Way to Resolve (preupgradecheck) Findings? PowerShell's Got Your Back!

Performance is a concern of every system administrator, unless you're an Information Assurance Kind of guy and then you'd probably just assume see the server switched off (just a bit of a nudge), and if SharePoint is your poison watch out for Closed WebParts throughout your site. Closed WebParts are still attached to your page, are temporarily hidden but they do load when your page loads and if there are a number of them or any with Fatal Errors you're unecessarily impacting page load times and probably filling your logs with errors that you're having a difficult time tracking down. Worse yet if you plan a migration from SharePoint 2007 to 2010 and run the preupgradecheck STSADM command you'll find yourself with a nice list of things that could be problems during an upgrade and no clear path to resolve things in that list.
<!--more-->
The handy PowerShell script below can help with both. It will iterate through all of the web applications on your server and the pages at the root of each site (it doesn't look at pages in libraries which could also be an issue) and deletes closed WebParts as well as reporting WebParts that themselves are reporting a Fatal Error. Can make site cleanup much faster and perk up you site performance, especially if you have an older SharePoint Farm that's been through the ringer.


 #Load assemblies  
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")> $null  
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Portal")> $null  
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Security")> $null  
 $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local;  
 $services = @($farm.Services | where -FilterScript {$_.GetType() -eq [Microsoft.SharePoint.Administration.SPWebService]})  
 foreach ($service in $services)  
 {  
   foreach($app in $service.WebApplications)  
   {  
     $sites = $app.Sites  
     foreach ($site in $sites)  
     {      
       if (!$site.ServerRelativeUrl.Contains("ssp/"))  
       {  
            foreach ($currentWeb in $site.AllWebs)  
            {  
                 $pages = $currentWeb.Files | Where-Object {$_.Name -match ".aspx"}  
                 Write-Host "Analyzing Web $($currentWeb.Url)."  
                 foreach($currentPage in $pages)  
                 {  
                      Write-Host "Analyzing Page $($currentPage.ServerRelativeUrl)."  
                      if ($currentPage.CheckedOutByUser -ne $NULL)  
                      {  
                           $currentPage.CheckIn("Administratively Checked-In");  
                      }  
                      $url = $currentPage.ServerRelativeUrl;  
                      if ($url -eq $NULL)  
                      {  
                           continue  
                      }  
                      $webPartManager = $currentWeb.GetLimitedWebPartManager($url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)  
                      $closedWebparts = New-Object System.Collections.ArrayList  
                      $badWebparts = New-Object System.Collections.ArrayList  
                      foreach($webpart in $webPartManager.WebParts)  
                      {  
                           if($webpart.IsClosed)  
                           {  
                                $closedWebparts.add($webpart);  
                           }  
                           elseif ($webpart.FatalError)  
                           {  
                                $badWebparts.add($webPart)  
                           }  
               else  
               {  
                 $webPart.AllowClose = $FALSE;  
                 $webPart.AllowZoneChange = $TRUE;  
               }  
                      }  
                      foreach($webpart in $closedWebparts)  
                      {  
                           Write-Host "Deleting closed webpart $($webpart.Title) on page $($currentPage.ServerRelativeUrl)."  
                           $webPartManager.DeleteWebPart($webpart);  
                      }  
                      foreach($webpart in $badWebparts)  
                      {  
                           Write-Host "$($webpart.ID) on $($currentPage.ServerRelativeUrl) is reporting $($webpart.ImportErrorMessage) "  
                           #$webPartManager.DeleteWebPart($webpart);  
                      }  
                 }  
                 $currentWeb.Dispose()  
            }  
       }  
          $site.Dispose()  
     }  
   }  
 }