5

A client migrated from 2007 to 2010 doing a database detach/reattach without checking the database for orphaned objects first. I whipped up a PowerShell script to programmatically remove orphaned WebParts that generate "Missing server side dependencies" errors in CA Health Analysis like:

[MissingWebPart] WebPart class [GUID] is referenced [1] times in the database [ContentDBName], 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 [ContentDBName], but are not installed on the current farm. Please install any feature or solution which contains these web parts.

When I try to remove a WebPart programmatically it tells me:

Exception calling "DeleteWebPart" with "1" argument(s): "The file is not checked out.  You must first check out this document before making changes."
At C:\RemoveWebParts.ps1:47 char:31
+                 $spWpManager.DeleteWebPart <<<< ($spWpManager.Webparts[$webpartId])
+ CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

So I implemented code to check out the page and check it back in after it's removed (if I checked it out) and now it's telling me:

Exception calling "DeleteWebPart" with "1" argument(s): "The file is currently checked out or locked for editing by another user."
At C:\RemoveWebParts.ps1:53 char:31
+                 $spWpManager.DeleteWebPart <<<< ($spWpManager.Webparts[$webpartId])
+ CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Which obviously is an issue. When it's not checked out it says it has to be checked out, and when it is checked out it says it's checked out by another user (even though the SharePoint 2010 Management Shell is running as my user, and I can verify my user is the user the page is checked out to).

Why could this be? How can I resolve it?

Edit

Here is the code (site hierarchy traversal omitted for brevity):

$spWpManager = $spweb.GetLimitedWebPartManager($WebPageUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
$webparts = @()

if ($item.File.CheckOutType -ne "None")
{
    $checkedOut = $checkedOut + $WebPageUrl + ","
}

foreach($spwebpart in $spWpManager.Webparts)
{
    if($spwebpart.Title -eq $wpName)
    {
        $webparts = $webparts + $spwebpart.ID
    }
}

foreach($webpartId in $webparts)
{
    if (!$bool)
    {
        $item.File.CheckOut()
        $bool=$true
    }

    $spWpManager.DeleteWebPart($spWpManager.Webparts[$webpartId])
}

if ($bool)
{
    $item.File.CheckIn()
    $bool=$false
}
6
  • Can you post the code?
    – Dave Wise
    Aug 6, 2012 at 21:44
  • Are you running this code elevated? Is the same user used to check out as you use to delete? (yeah share code) Aug 6, 2012 at 22:12
  • 1
    I edited the post to add the PowerShell code Aug 7, 2012 at 12:58
  • @AndersRask I'm not running the code elevated (danlarson.com/…). And yes it is the same user. I verified that the PowerShell process is running as the same user that the page was successfully checked out to. The page was successfully checked in (probably should use Publish()) following the run. The WebPart doesn't get removed, it throw the errors above on $spWpManager.DeleteWebPart(). Aug 7, 2012 at 13:05
  • 1
    I usually check $file.CheckedOutByUser.Id and see if this matches $file.Web.CurrentUser.Id and throw an error ("not checked out by me"). If you need to Publish() or Approve() depends on what kind of publishing you are using. If you have enabled minor versions you need to publish ($list.EnableMinorVersions > $file.Publish("")) if you have enabled moderation you need to approve ($list.EnableModeration > $file.Approve("")) Aug 13, 2012 at 13:51

2 Answers 2

1

To make this work you need to check out the file before you assign the web part manager. A very quick solotion is to assign the $spWpManager again after File.CheckOut() - like this:

$spWpManager = $spweb.GetLimitedWebPartManager($WebPageUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
$webparts = @()

if ($item.File.CheckOutType -ne "None")
{
    $checkedOut = $checkedOut + $WebPageUrl + ","
}

foreach($spwebpart in $spWpManager.Webparts)
{
    if($spwebpart.Title -eq $wpName)
    {
        $webparts = $webparts + $spwebpart.ID
    }
}

foreach($webpartId in $webparts)
{
    if (!$bool)
    {
        $item.File.CheckOut() # File checkout here
        $bool=$true
    }

    # Quick fix, assign the $spWpManager again here.
    $spWpManager = $spweb.GetLimitedWebPartManager($WebPageUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);    
    $spWpManager.DeleteWebPart($spWpManager.Webparts[$webpartId])
}

if ($bool)
{
    $item.File.CheckIn()
    $bool=$false
}
4
  • Can you explain why this is? I gave up on this long ago, but I'd like to understand why it's necessary to do it this way. Feb 7, 2013 at 14:25
  • @rjcjp3 Probably because you get the web part manager reference in a checked in mode, rather than a checked out mode.
    – Benny Skogberg
    Feb 7, 2013 at 14:53
  • Looks like this is the same problem: sharepoint.stackexchange.com/questions/52814/… Thanks! This question has been unanswered for 6 months with a bounty and everything. Feb 7, 2013 at 15:18
  • @rjcup3 You're welcome! All search strings I added I always ended up here - so when my similar problem was solved, I just had to answer this question. Hopefully it'll help others stuck in the same problem we had.
    – Benny Skogberg
    Feb 7, 2013 at 16:32
0

Have you tried SPCheckedOutFile.TakeOverCheckOut method? Otherwise you can discard changes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.