How to delete a document locked by another user in Sharepoint using JavaScript

When you open a file from Sharepoint, it will receive a short term lock that will prevent others to change some properties on the file.

This protection can be useful, but also very annoying, for example when the file is not closed properly, then the lock could stay « forever ».

There are many posts on the web about it.

I found one that has been super useful: https://pholpar.wordpress.com/2014/04/07/how-to-use-javascript-to-delete-short-term-locks-from-documents-opened-from-sharepoint/
The author explains very well the different steps what I’m trying to summarize:

  1. Send a request to _vti_bin/_vti_aut/author.dll with special headers/body
  2. Auth.dll will provide the lockid
  3. Send a request to _vti_bin/cellstorage.svc/CellStorageService with special headers/body, included the lockid
  4. The file is unlocked

The code to send to CellStorageService, and provided by the author, didn’t work for me. I’ve had to use Fiddler and open the document into Office on my computer to see the kind of requests send by it to unlock a document. Based on it, I’ve re-built the code and you can find my solution below.

Tested on Sharepoint 2013 On-Promise only. I don’t know if this solution works for Sharepoint Online or other version.
Also note that I use $SP().ajax() from SharepointPlus, but it’s equivalent to the $.ajax from jQuery.

// full path to the document
var docUrl = "https://website.com/website/Doc_Library/Test.docx";

// start by querying author.dll to find the lockid and the user who locked it
$SP().ajax({
  url: 'https://website.com/website/_vti_bin/_vti_aut/author.dll',
  headers:{
    "Content-Type": "application/x-www-form-urlencoded",
    "MIME-Version": "1.0",
    "Accept": "auth/sicily",
    "X-Vermeer-Content-Type": "application/x-www-form-urlencoded"
  },
  body: 'method=getDocsMetaInfo%3a14%2e0%2e0%2e6009&url%5flist=%5b' + encodeURIComponent(docUrl) + '%5d&listHiddenDocs=false&listLinkInfo=false',
}).then(function(source) {
  // go thru the source page returned to find the lockid and current user
  var nextLine = false;
  var ret = { "lockid":"", "user":"", when:"" };
  source.split("\n").forEach(function(line) {
    if (line.indexOf("vti_sourcecontrollockid") !== -1) nextLine="lockid"; // vti_sourcecontrollockid -> the lockid to use later
    else if (line.indexOf("vti_sourcecontrolcheckedoutby") !== -1) nextLine="user"; // vti_sourcecontrolcheckedoutby -> username of the user who locked it
    else if (line.indexOf("vti_sourcecontrollockexpires") !== -1) nextLine="when"; // vti_sourcecontrollockexpires -> when the server is supposed to unlock it
    else if (nextLine !== false) {
      ret[nextLine] = line.slice(7).replace(/&#([0-9]|[1-9][0-9]|[[01][0-9][0-9]|2[0-4][0-9]|25[0-5]);/g, function (str, match) { return  String.fromCharCode(match); });
      nextLine = false;
    }
  });

  if (!ret.lockid) { alert("Not Locked") }
  else {
    // compose a request based on what Microsoft Office sends to the Sharepoint server
    // found using Fiddler
    var releaseLockReq = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/><RequestCollection CorrelationId="{96A244BD-D13B-4696-9355-231FB673BC4F}" xmlns="http://schemas.microsoft.com/sharepoint/soap/"><Request Url="'+docUrl+'" UseResourceID="true" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="16.0.8201.2102" MetaData="1031" RequestToken="1"><SubRequest Type="ExclusiveLock" SubRequestToken="1"><SubRequestData ExclusiveLockRequestType="ReleaseLock" ExclusiveLockID="'+ret.lockid+'"/></SubRequest></Request></RequestCollection></s:Body></s:Envelope>';

    // we send it to the webservice cellstorage.svc
    $SP().ajax({
      url:'https://website.com/website/_vti_bin/cellstorage.svc/CellStorageService',
      body:releaseLockReq,
      headers:{
        'Content-Type':'text/xml; charset=UTF-8',
        'SOAPAction': "http://schemas.microsoft.com/sharepoint/soap/ICellStorages/ExecuteCellStorageRequest"
      }
    })
    .then(function(res) {
      if (res.indexOf('ErrorCode="Success"') !== -1) alert("Success") // the file has been unlocked
      else alert("Failed")
    })
  }
})

I hope it will be useful to someone else!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*