質問

We are using SP2013 with OWA installed. Users often complain about a file stored in SharePiont being locked by another user not in office. Error is "The file "xxxx" is locked for exclusive use by domain\user". Microsoft KB said the lock will be released after the file is idle for 10 minutes. We all know that it is not true. It usually take days for the lock release.

After some investigation, I found these kind of lock is called "ShortTerm" Lock (SPFile.SPCheckedOutStatus.ShortTerm). The lock can be released by PowerShell:

$w = get-spweb "http://sharepoint.com"
$l = $w.lists["Shared document"]
$i = $l.GetItemById(123)
$i.File.ReleaseLock($i.File.LockId)

However, above command require server access. It is not applicable to us because we have very restrictive policy. We cannot just walk in the server room and run the command.

Is it possible to process the lock release with CSOM or Javascript under the permission of Site Collection Admin?

役に立ちましたか?

解決

AFAIK, nothing in the client-side API can allow this.

However, there's an old technology called "Front-Page RPC" (the name itself shows you how old it is!) that may be still available on SP2013 (even if it's kind of deprecated/not really documented). It is still there since it's used by Office applications to communicate with SharePoint.

FP RPC is a kind of WebDav protocol, i.e. it's HTTP requests (mostly POST requests) you must send to the server. I have a sample in VB.NET (sorry, it's VB.NET, I don't find the C# version in my archives):

Public Sub UncheckoutDocument(ByVal SiteUrl As String, ByVal FileUrl As String)
    SendPostRequest(SiteUrl + "/_vti_bin/_vti_aut/author.dll", _
        "method=uncheckout+document%3a6%2e0%2e2%2e5523&service%5fname=%2fsites%2fcompta&document%5fname=" & HttpUtility.UrlEncode(FileUrl) & "&force=true&rlsshortterm=true")
End Function

Private Function SendPostRequest(ByRef Url As String, ByRef Body As String) As String
    Dim Request As WinHttp.WinHttpRequest
    Request = New WinHttp.WinHttpRequestClass
    Request.Open("POST", Url, False)
    Request.SetCredentials("user", "password", 0)

    Request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    Request.SetRequestHeader("X-Vermeer-Content-Type", "application/x-www-form-urlencoded")
    Request.SetRequestHeader("MIME-Version", "1.0")
    Request.SetRequestHeader("User-Agent", "MSFrontPage/6.0")

    Request.Send(Body)

    Return Request.ResponseText
End Function

The problem here is with authentication. The code above is for Windows authentication. It won't work for Office 365.
What you have to do is remove the line Request.SetCredentials("user", "password", 0) to set instead an authentication cookie. You can probably get that authentication cookie first by using, for instance, the MsOnlineClaimsHelper class I've just found at http://www.wictorwilen.se/Post/How-to-do-active-authentication-to-Office-365-and-SharePoint-Online.aspx.

他のヒント

If you're looking for a client-side solution for Sharepoint 2013 that can be executed in JavaScript, I found some good stuff on this blog that I have updated on mine.

To unblock the short term lock for a file:

  1. Send a request to _vti_bin/_vti_aut/author.dll with special headers/body to find the lockid
  2. Send a request to _vti_bin/cellstorage.svc/CellStorageService with a formatted body that includes the lockid
  3. The file is unlocked

Tested for Sharepoint 2013 On-Promise only. I don’t know if this solution works for Sharepoint Online or other version.
Please 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":"" };
  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 (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="'+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")
    })
  }
})
ライセンス: CC-BY-SA帰属
所属していません sharepoint.stackexchange
scroll top