For the benefit of future generations, a file lock can be removed via Powershell on an on-premises installation of SharePoint 2010 or later.
How can this happen?
Files can get locked when a client application fails to update the server-side file token that indicates whether a file is currently being edited. (This type of lock is application-specific, and thus different from the explicit Check In/Check Out functionality provided by SharePoint document libraries.) This scenario comes up when computers (or applications) crash unexpectedly, or get disconnected from the network.
With Office products, the file lock is supposed to expire automatically after ten minutes, and this is usually the case. Sometimes a lock seems to persist, which may be the result of browser caching problems or bugs in the way client applications handle the file locks.
How can we fix it?
The Powershell for removing a file lock is as follows:
$web = get-spweb "http://myfarm/mysite/mysubsite"
$list = $web.Lists["My Library"]
$item = $list.Items.GetItemById(123)
$item.File.ReleaseLock($item.File.LockId)
$web.Dispose()
Replace the placeholders with values appropriate to your environment/list/document; use the actual subsite URL in the get-spweb
cmdlet, use the library's title to retrieve it from the $web.Lists
collection, and use the actual ID of the problem document as the parameter in GetItemById()
.
This Powershell should be executed from a web front end server on your SharePoint farm. You'll need to load the PS snapin for SharePoint cmdlets such as get-spweb
, unless you use the SharePoint Management Shell installed with SharePoint, which starts a Powershell session with the SharePoint snapins already loaded.
Use impersonation if necessary to release the lock
If you run the above Powershell and still run up against an error like this...
Exception calling "ReleaseLock" with "1" argument(s): "The file XXXXXXX is locked for exclusive use by XXXXX"
...you can try using impersonation to release the lock. This is accomplished by using the LockedByUser
property of the file to get a reference to the user you need to impersonate, then creating a new SPSite object instance passing in that user's token as a second parameter.
$web = get-spweb "http://myfarm/mysite/mysubsite"
$list = $web.Lists["My Library"]
$item = $list.Items.GetItemById(123)
$userId = $item.File.LockedByUser.ID
$user = $web.AllUsers.GetById($userId)
$impSite = New-Object Microsoft.SharePoint.SPSite($web.Url, $user.UserToken);
$impWeb = $impSite.OpenWeb();
$impList = $impWeb.Lists[$list.Title];
$impItem = $impList.GetItemById($item.ID);
$impItem.File.ReleaseLock($impItem.File.LockId)
$impWeb.Dispose()
$impSite.Dispose()
$web.Dispose()
$impSite
and $impWeb
in the above example are SPSite and SPWeb objects using the impersonated user token.