Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I'm writing a powershell function to add custom webparts (i.e. not Out Of The Box webparts such as ContentEditor) to publishing pages on a SharePoint Server 2010 site. I encountered a frustrating issue when trying to add / delete webparts from the page whereby SPLimitedWebPartManager was throwing the following error:

    --------------------------------------------------
    -- Error information
    --------------------------------------------------
    Line Number: 198
    Offset: 27
    Command: 
    Line:                   $wpManager.AddWebPart($wp, $WebPartSettings.Zone, $WebPartSettings.ZoneIndex)
    Error Details: Exception calling "AddWebPart" with "3" argument(s): "The file is not checked out.  You must first check out this document before making changes."
    Unbound args: 
    Exception: System.Management.Automation.MethodInvocationException: Exception calling "AddWebPart" with "3" argument(s): "The file is not checked out.  You must first check out this document before making changes." ---> Microsoft.SharePoint.WebPartPages.WebPartPageUserException: The file is not checked out.  You must first check out this document before making changes.
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.SaveSomeChanges(SPLayoutProperties layoutProperties)
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.MakeSpaceForWebPart(WebPart webPartToPlace, Int32 zoneIndex, String zoneID, Boolean storeInPendingChangesList)
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.OnWebPartAddingCore(SPSupersetWebPart superset, Boolean throwIfLocked)
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartInternal(SPSupersetWebPart superset, Boolean throwIfLocked)
       at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPartInternal(WebPart webPart, String zoneId, Int32 zoneIndex, Boolean throwIfLocked)
       at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPart(WebPart webPart, String zoneId, Int32 zoneIndex)
       at AddWebPart(Object , Object[] )
       at System.Management.Automation.DotNetAdapter.AuxiliaryMethodInvoke(Object target, Object[] arguments, MethodInformation methodInformation, Object[] originalArguments)

I have Write-Host statements on the line before calling $wpManager.AddWebPart and $wpManager.DeleteWebPart that print out the values of CheckedOutBy, CheckOutStatus, etc for the PublishingPage that show that the file is checked out but I still get an error stating that the file is not checked out.

I found this post:

Possible to checkout a file using PowerShell?

but their issue was the file wasn't actually checked out, whereas mine apparently is checked out.

Sample output from Write-Host here:

    CheckOutType: Online
    CheckOutStatus: LongTerm
    CheckedOutBy: MYDOMAIN\user.name

On another question, Anders Rask suggested the poster compare the userid of the PublishingPage.ListItem.File.CheckedOutBy field with the userid of PublishingPage.Web.CurrentUser but these returned the exact same value.

My PowerShell code is:

    function Add-WebPartToPage

        Param
        (
            [Microsoft.SharePoint.SPWeb]$SpWeb,
            [Microsoft.SharePoint.Publishing.PublishingPage]$PublishingPage,
            [System.Xml.XmlNode]$WebPartSettings,
            [string]$LogName
        )
        Process
        {
            if ($PublishingPage -eq $null)
            {
                Write-Host "Cannot add webparts to page as page is null"
                return
            }

            if ([string]::IsNullOrEmpty($PublishingPage.Url))
            {
                Write-Host "Unable to access webparts for page as page url is undefined"
                return
            }

            Try
            {
                $serverRelativeUrl = $SpWeb.ServerRelativeUrl + "/" + $PublishingPage.Url
                Write-Host "ServerRelativeUrl:" $serverRelativeUrl

                [Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager]$wpManager = $SpWeb.GetLimitedWebPartManager($serverRelativeUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
                if ($wpManager -eq $null)
                {
                    Write-Host "Failed to retrieve WPManager"
                    return
                }

                # Page must be checked out before making any changes
                if ($PublishingPage.ListItem.File.CheckOutType -eq "None")
               {
                    Write-Host "checking out file" $PublishingPage.Title
                   $PublishingPage.ListItem.File.CheckOut()
               }

                $pageWebparts = $wpManager.WebParts

                if ($pageWebparts -eq $null -or $pageWebparts.Count -eq 0)
                {
                    Write-Host "No webparts on page " $PublishingPage.Name
                }
                else
                {
                    $pageWebparts | ForEach-Object {
                        Write-Host "Webpart:" $_.Name
                    }

                    $existingWebPart = $pageWebparts | Where-Object { $_.Name -eq $WebPartSettings.Name }

                    if ($existingWebPart -ne $null)
                    {
                        $file = $PublishingPage.ListItem.File
                        Write-Host "Checked out by" $file.CheckedOutBy
                        Write-Host "Current user:" $file.Web.CurrentUser
                        Write-Host "Locked by:" $file.LockedByUser
                        Write-Host "LockType:" $file.LockType
                        Write-Host "Removing webpart from page..."
                        #$wpManager.DeleteWebPart($existingWebPart)
                    }
                }           

                Write-Host "CheckOutType:" $PublishingPage.ListItem.File.CheckOutType
                Write-Host "CheckOutStatus:" $PublishingPage.ListItem.File.CheckOutStatus
                Write-Host "CheckedOutBy:" $PublishingPage.ListItem.File.CheckedOutBy

                Write-Host "Adding webpart"

                [System.Xml.XmlTextReader]$oxmlReader = new-object System.Xml.XmlTextReader($WebPartSettings.FileLocation)

                [string]$errorMsg = ""
                $wp = $wpManager.ImportWebPart($oxmlReader, [ref]$errorMsg)
                Write-Host "Import output:" $errorMsg

                $wpManager.AddWebPart($wp, $WebPartSettings.Zone, $WebPartSettings.ZoneIndex)

                $PublishingPage.CheckIn("Added webpart")
            }
            Catch
            {
                Write-Host $Error[0]

                if ($PublishingPage -ne $null -and $PublishingPage.ListItem.File.CheckOutType -ne "none")
                {
                    Write-Verbose "Error occurred whilst adding webparts to the page. Undoing checkout"
                    $PublishingPage.ListItem.File.UndoCheckOut()
                }

                throw $Error[0]
            }       
        }
    }

NOTE: The $WebPartSettings comes from an XML config file

    <webpart name="MyWebPart.webpart" zone="Header" zoneIndex="0" FileLocation="C:\Releases\MyWebPart\MyWebPart.webpart">
    </webpart>
share|improve this question
    
Same problem as: sharepoint.stackexchange.com/questions/42720/… –  RJ Cuthbertson Feb 7 '13 at 15:19
add comment

1 Answer 1

up vote 6 down vote accepted

The problem turned out to be where I was checking out the page. The page must be checked out before the SPLimitedWebPartManager is retrieved.

function Add-WebPartToPage

    Param
    (
        [Microsoft.SharePoint.SPWeb]$SpWeb,
        [Microsoft.SharePoint.Publishing.PublishingPage]$PublishingPage,
        [System.Xml.XmlNode]$WebPartSettings,
        [string]$LogName
    )
    Process
    {
        if ($PublishingPage -eq $null)
        {
            Write-Host "Cannot add webparts to page as page is null"
            return
        }

        if ([string]::IsNullOrEmpty($PublishingPage.Url))
        {
            Write-Host "Unable to access webparts for page as page url is undefined"
            return
        }

        Try
        {
            $serverRelativeUrl = $SpWeb.ServerRelativeUrl + "/" + $PublishingPage.Url
            Write-Host "ServerRelativeUrl:" $serverRelativeUrl

            # Page must be checked out before making any changes
            if ($PublishingPage.ListItem.File.CheckOutType -eq "None")
           {
                Write-Host "checking out file" $PublishingPage.Title
               $PublishingPage.ListItem.File.CheckOut()
           }

           [Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager]$wpManager = $SpWeb.GetLimitedWebPartManager($serverRelativeUrl, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
            if ($wpManager -eq $null)
            {
                Write-Host "Failed to retrieve WPManager"
                return
            }

            $pageWebparts = $wpManager.WebParts

            if ($pageWebparts -eq $null -or $pageWebparts.Count -eq 0)
            {
                Write-Host "No webparts on page " $PublishingPage.Name
            }
            else
            {
                $pageWebparts | ForEach-Object {
                    Write-Host "Webpart:" $_.Name
                }

                $existingWebPart = $pageWebparts | Where-Object { $_.Name -eq $WebPartSettings.Name }

                if ($existingWebPart -ne $null)
                {
                    $file = $PublishingPage.ListItem.File
                    Write-Host "Checked out by" $file.CheckedOutBy
                    Write-Host "Current user:" $file.Web.CurrentUser
                    Write-Host "Locked by:" $file.LockedByUser
                    Write-Host "LockType:" $file.LockType
                    Write-Host "Removing webpart from page..."
                    #$wpManager.DeleteWebPart($existingWebPart)
                }
            }          

            Write-Host "CheckOutType:" $PublishingPage.ListItem.File.CheckOutType
            Write-Host "CheckOutStatus:" $PublishingPage.ListItem.File.CheckOutStatus
            Write-Host "CheckedOutBy:" $PublishingPage.ListItem.File.CheckedOutBy

            Write-Host "Adding webpart"

            [System.Xml.XmlTextReader]$oxmlReader = new-object System.Xml.XmlTextReader($WebPartSettings.FileLocation)

            [string]$errorMsg = ""
            $wp = $wpManager.ImportWebPart($oxmlReader, [ref]$errorMsg)
            Write-Host "Import output:" $errorMsg

            $wpManager.AddWebPart($wp, $WebPartSettings.Zone, $WebPartSettings.ZoneIndex)

            $PublishingPage.CheckIn("Added webpart")
        }
        Catch
        {
            Write-Host $Error[0]

            if ($PublishingPage -ne $null -and $PublishingPage.ListItem.File.CheckOutType -ne "none")
            {
                Write-Verbose "Error occurred whilst adding webparts to the page. Undoing checkout"
                $PublishingPage.ListItem.File.UndoCheckOut()
            }

            throw $Error[0]
        }      
    }
}
share|improve this answer
    
There are a lot of other bogus fixes on the web which claim to fix this problem, but thumbs up, this seems to be only one that does the trick. –  Nick Larter Apr 23 '13 at 5:37
    
Yes. Absolutely Correct. –  Harsh Bhavsar Oct 9 '13 at 9:25
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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