This item cannot be updated because it is locked as read-only

Had to call in Microsoft Support to help unlock files that were marked as read-only. Some files appeared to be locked, but using the UI, they couldn’t be unlocked, declared as a record, or edited.

Error: This item cannot be updated because it is locked as read-only
Error: The file “your file string” is checked out for editing by SHAREPOINT\system

This script was setup to run on a SharePoint 2010 instance. If you need to run it on another version, try updating the $sharePointAssembly line.
To unlock a file, input the URL of the file in the line that starts with $fileUrl.


$recordFields =
  "_vti_ItemHoldRecordStatus",
  "_vti_ItemDeclaredRecord"

$recordProperties =
  "ecm_RecordRestrictions",
  "ecm_ItemLockHolders",
  "ecm_ItemDeleteBlockHolders"

$fileUrl = "http://siteURL/siteCollection/libraryName/folder/subFolder/fileName.pdf"

$sharePointAssembly = [System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")

Add-Type -TypeDefinition @"
using Microsoft.SharePoint;

public class EventsDisabler : SPEventReceiverBase
{
  public EventsDisabler() {}
  
  public bool EventsDisabled
  {
    get { return !EventFiringEnabled; }
    set { EventFiringEnabled = !value; }
  }
}
"@ -ReferencedAssemblies $sharePointAssembly

Write-Host "Getting site collection at $fileUrl..."
[Microsoft.SharePoint.SPSite]$site = New-Object Microsoft.SharePoint.SPSite($fileUrl)
if ($site -eq $null) { exit }
$siteUrl = $site.Url
Write-Host "Found site collection $siteUrl"
Write-Host ""

Write-Host "Getting web at $fileUrl..."
[Microsoft.SharePoint.SPWeb]$web = $site.OpenWeb()
if ($web -eq $null) { exit }
$webTitle = $web.Title
Write-Host "Found web $webTitle"
Write-Host ""

Write-Host "Verifying current user is System Account"
$web.CurrentUser.ID
$site.SystemAccount.ID
if ($web.CurrentUser.ID -ne $site.SystemAccount.ID)
{
  Write-Error "Please run this script as System Account" -Category PermissionDenied
  #exit
}
Write-Host ""

Write-Host "Getting list at $fileUrl..."
Write-Host $fileUrl
[Microsoft.SharePoint.SPList]$list = $web.GetList($fileUrl)
if ($list -eq $null) { exit }
$listTitle = $list.Title
Write-Host "Found list $listTitle"
Write-Host ""

Write-Host "Getting list item at $fileUrl..."
[Microsoft.SharePoint.SPListItem]$listItem = $web.GetListItem($fileUrl)
if ($listItem -eq $null) { exit }
$listItemName = $listItem.Name
Write-Host "Found list item $listItemName"
Write-Host ""

$eventsDisabler = New-Object EventsDisabler
$eventsOriginallyDisabled = $eventsDisabler.EventsDisabled
if ($eventsOriginallyDisabled -eq $false)
{
  Write-Host "Disabling events"
  $eventsDisabler.EventsDisabled = $true
  Write-Host ""
}

$didWork = $false
$itemNeedsUpdate = $false

#Discard any check-out
if ($listItem.File -ne $null -and $listItem.File.CheckOutType -ne [Microsoft.SharePoint.SPFile+SPCheckOutType]::None)
{
  Write-Host "Undoing check-out"
  $listItem.File.UndoCheckOut()
  $didWork = $true
}
else
{
  Write-Host "No file or file is not checked out"
  Write-Host ""
}

#Iterate the Record fields and set all values to null
foreach($recordField in $recordFields)
{
  if ($listItem.Fields.ContainsField($recordField) -eq $true -and $listItem[$recordField] -ne $null)
  {
    $recordFieldValue = $listItem[$recordField]
    Write-Host "$recordField = $recordFieldValue"
    Write-Host "Setting $recordField to null"
    $listItem[$recordField] = $null
    $didWork = $true
    $itemNeedsUpdate = $true
  }
}

#Iterate the Record properties and remove any that exist
foreach($recordProperty in $recordProperties)
{
  if ($listItem.Properties.ContainsKey($recordProperty) -eq $true)
  {
    $recordPropertyValue = $listItem.Properties[$recordProperty]
    Write-Host "$recordProperty = $recordPropertyValue"
    Write-Host "Removing property $recordProperty"
    $listItem.Properties.Remove($recordProperty)
    $didWork = $true
    $itemNeedsUpdate = $true
  }
}

#Remove the icon Record lock overlay
if ($listItem.IconOverlay -eq "lockoverlay.png")
{
  Write-Host "Removing the icon Record lock overlay"
  $listItem.IconOverlay = $null
  $didWork = $true
  $itemNeedsUpdate = $true
}

if ($didWork -ne $true)
{
  Write-Host "No changes were made"
}
Write-Host ""

#Update the item
if ($itemNeedsUpdate -eq $true)
{  
  Write-Host "Updating item"
  $listItem.SystemUpdate()
  
  Write-Host ""
}

if ($eventsOriginallyDisabled -ne $true)
{
  Write-Host "Enabling events"
  $eventsDisabler.EventsDisabled = $false
  Write-Host ""
}

$web.Dispose()
$site.Dispose()

4 thoughts on “This item cannot be updated because it is locked as read-only

  1. This is helpful but calling SystemUpdate gives me the same “locked as read-only” error I was getting in the first place. But that is my only symptom, no issues through the browser UI.

  2. Ya, they both gave the same result. But I was able to work around it in my case with BypassLocks() — [Microsoft.Office.RecordsManagement.RecordsRepository.Records]::BypassLocks($item, {$item.Update()})

    My records were in a weird state where following a call to UndeclareItemAsRecord() I would get an error, but I would see a lock icon (even after refreshing the page) yet in the Compliance Details it would show as undeclared. The _vti_ItemHoldRecordStatus was 1, and one of the other properties was non null. Also I couldn’t get your EventsDisabler declaration to work, it was giving me a file not found, some tmp folder thing. So I commented that out.

    Anyway thanks for posting this a while back, it definitely helped me out!

Leave a Reply

Your email address will not be published. Required fields are marked *