Solution to Unlocking Locked Files in SharePoint 2010

Recently we came across a problem with our SharePoint 2010 (SP1) system (that we’ve been upgrading from SharePoint 2007), where we use a custom work-flow process to clean up a set of files once the work-flow has been completed.

To achieve this we use a timer job that is kicked off periodically which removes the files associated with any newly completed work-flows.

The issue we had is that even though the users are completing the work flow, which means they have finished with the files we have no way of being sure they have closed all the files they were working on as part of the workflow, files maybe left open in office or in some situations office may have crashed! In both these circumstances files are left with short term locks as though they are being editied and can’t be deleted, yes you can wait for the default short term lock timeout (in the crash scenario) however this won’t help you if the user still has the file open, as Office will continue to renew its short term lock.

Our solution to this problem when we were on SharePoint 2007 was to make an RPC call via HTTP to the author.dll, this enabled our workflow clean-up timer job to mimic the same RPC over HTTP call Office makes when you close a document this releases the lock on any file (it’s amazing what you can find out with fiddler).  This worked fine for us on SP2007, however on SP2010, although it didn’t error if failed to unlock the files, so the delete process in the timer job couldn’t tidy up the documents.

We spent some time digging around inside the SharePoint 2010 assemblies (reflector to the rescue), looking into the content databases etc.., trying to spot any differences in internal implementation between SP2007 & SP2010, that might give us a clue as to why our RPC call over HTTP was no longer working.

In conjunction with a bit of SQL tracing we found the stored  procedure proc_UncheckoutDocument within SharePoint’s content database that unlocks files when the RPC method on SP2010 is invoked, this procedure contains logic that checks to make sure the SharePoint user id passed to the proc matches the user who has the document checked out, and in our case this isn’t the case as the SharePoint\System user is attempting to delete the documents (our timer jobs run under this context), this procedure has a forceunlock parameter, that if set changes an internal logic path in the procedure to allow the unlock to happen regardless , interestingly the HTTP RPC call to the author.dll also had this parameter.  So we thought no problem, lets just use the force unlock, however it appears that a small bug exists as when we had SQL tracing on we could never get the call via RPC to pass the forceunlock parameter down the the stored proc in the DB, it was always being passed as 0, even with the force unlock parameter set to 1 in the RPC call.

Our next port of call led us to a new API on the SPFile object for SharePoint 2010, ReleaseLock this appeared to offer what we wanted but again we ran into the same problem as the RPC method, our timer process wasn’t running under the user context so it failed to unlock the file, just to test things we tried calling the function manually while running a test component under the user context who had a file checked out or short term locked and it does indeed release the lock.

We next thought we need to impersonate the user who has the file open, trouble is this isn’t possible as we don’t hold the user credentials of all our users to create the runtime identity object from within our timer service.

After a little bit of headscratching, how we were going to solve this problem?

Our first clue was hmm hang on these user ID’s are SharePoint user ID’s from the userinfo table, not Windows identities, is there anyway we could create an SPSite context inside our timer job that uses this user ID rather than that of SharePoint\System?

Thankfully the SPSite object has a constructor that can take a SPUserToken object (I assume for this exact purpose) hmm what if we set this to the user who has the file checked out, we can do that by first getting the checked out SPUser from the SPFile.LockedByUser property, then use this to read the UserToken value we can do all this without needing to know the users credentials, then use this to create another SPSite with the correct user context, but will it work…

After a few minutes of development you can create a piece of prototype code, we do need to have two SPSite objects one from the Timer Service context SPWebApplication which will be associated with the SharePoint\System account to obtain the UserToken of the locked file, then another SPSite object created using the UserToken so we can unlock the file.

So if your stuggling to unlock files in a document library on SharePoint 2010 that others have left checked out, and you need to do it under the context of an account other than the user that has the file locked out, for example a timer job, give this approach a go it worked for us.

I take no responsibility for irate users, if you try this method to forcibly unlock a file while somebody really is still working on it, as they will likely lose the last set of changes!

You may find other methods mentioned on the internet about ways to do this by directly manipulating the tables in the SharePoint content database, such as this I would not recommend that you follow this approach, as interacting with and updating the databases directly in SharePoint may put you in breach of the EULA you signed up to when you installed SharePoint, and is definitly unsupported by Microsoft see here, so if you do it on a procduction system and break it your on your own, be warned !!

Tagged 2010, Checkout, Files, Lock, SharePoint, Unlock. Bookmark the permalink.

4 Responses to Solution to Unlocking Locked Files in SharePoint 2010

  1. Ritesh says:

    We are still on SP2007 and are facing this issue. Could you post your solution for SP2007.

    Thanks a lot,
    Rit

    • Hi,

      I can’t share the exact code with you due to intellectual rights issues, but can give you guidance.

      First thing to do is setup a data structure that contains the following info


      Dictionary myParams = new Dictionary();
      myParams.Add("method", "uncheckout document:12.0.0.4518");
      myParams.Add("service_name", "insert absolute URL to the sharepoint site here");
      myParams.Add("document_name", "insert url to file here");
      myParams.Add("force", "true");
      myParams.Add("rlsshortterm", "true or false depending on which type of lock you want to remove");

      Uses that structure to build a postData string using the UrlEncoding of the Key & Value Pairs in the data structure


      foreach (string key in myParams.Keys)
      {
      if (postData.Length > 0) postData += "&";
      postData += string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(myParams[key]));
      }

      Once you have your post data string, then you pass that info to the author DLL see below

      Turn the postData string into a byte[] using ASCIIEncoding

      Then create an HTTPWebRequest using the info below

      Target URL : “http://sharepoint server web url/_vti_bin/_vti_aut/author.dll”
      ContentType : “application/x-www-form-urlencoded”
      UserAgent : “FrontPage RPC Client X”
      Headers : “X-Vermeer-Content-Type”, “application/x-www-form-urlencoded”
      Accept : “auth/sicily”

      Use the default credentials of the SharePoint app pool when invoking this functionality from the sharepoint server via an ASPX layouts page or something similar.

      Then just use streams to get the request stream and write the data, then get the response stream and check for errors.

      If you run into issues install fiddler and capture the http traffic to / from SharePoint 2007 server when closing down an office application (Word 2003 is a good candidate) while editing a file directly from SharePoint document library, you will see it issue a similar set of commands to tell SharePoint that you are no longer editing the file, which then releases the short term lock being held.

      Cheers,

      Andy.

  2. sasar says:

    the fastest way to unlock is delete the file, but before that you need to copy the file to your PC or Desktop first. After you delete the file then you upload as new file with same name. Now the file should be ok.

    • Hi,

      If you do that though you loose all the previous versions of the file, and any meta data associated with it, I’m assuming you have versioning switched on, hence I wouldn’t recommend that approach.

      Thanks,

      Andy.

Leave a Reply

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

*