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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | $recordFields = "_vti_ItemHoldRecordStatus", "_vti_ItemDeclaredRecord" $recordProperties = "ecm_RecordRestrictions", "ecm_ItemLockHolders", "ecm_ItemDeleteBlockHolders" $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() |
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.
Did you try $listItem.Update() in place of SystemUpdate()?
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!
It work fine for me grate
Thanks for your time
Regards
TeeJay