Blog Post

Core Infrastructure and Security Blog
6 MIN READ

Using SharePoint Online CSOM to Capture Versions of Document Sets

Srinivas Varukala's avatar
Sep 28, 2020

 

With the latest release of SharePoint Online Client Components aka CSOM (Client-Side Object Model) (version: 16.1.20317.12000 or above), we now support methods to capture versions of Document Sets in SharePoint Online document libraries. This fills a major gap in our support for Document Sets in SharePoint Online as there was no way to capture versions of Document Sets automatically or programmatically. If you do a quick search online, you will see there are hundreds of posts where users are either asking for a way to capture version or document workarounds using JavaScript hacks and other unsupported methods. This also showcases that “Document Sets” are here to stay and will get all the support and enhancements in SharePoint Online.

 

Without the CSOM/API support, capturing a new version for a Document Set must be done manually through the ribbon or the ECB menu. This is true for both the classic and modern sites in both SPO and On-Premises. See below screenshot of the ECB menu to capture a version:

 

This API powering the “Capture Version” functionality is now generally available to everyone through the latest CSOM release. I am glad to share that I personally worked on a Design Change Request (DCR) on behalf of my customer to get this approved from Product Group. DCR is our internal process to make a business justification with enough evidence that a certain feature is needed/modified etc. That’s one of the many ways Product Group takes feedback from field broadening our impact in this role as a Customer Engineer (formerly known as Premier Field Engineer).

 

Here are short snippets of C# sample code that shows how the CSOM code works.

 

Start with basic CSOM authenticate and then get a site title:

 

 

 

string userName = "userid@Contoso.OnMicrosoft.com";
SecureString password = ConvertToSecureString("secretpassword");
var ctx = new ClientContext("https://Contoso.sharepoint.com/sites/ModernTeamSite");
ctx.Credentials = new SharePointOnlineCredentials(userName, password);
ctx.Load(ctx.Web);
ctx.ExecuteQuery();
Console.WriteLine(ctx.Web.Title);

 

 

 

Now that you have your ClientContext object ready. You can now request all the Document Set items from the library. Then request the version collection for each document set item.

 

 

 

var list = ctx.Web.Lists.GetByTitle("Documents");
//Use below two lines if you want to load a specific item by id
//var item = list.GetItemById(26);
//ctx.Load(item, l=>l.ContentType);

var query = new CamlQuery()
{
    ViewXml = String.Format("<View><Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>Document Set</Value></Eq></Where></Query></View>")
};

ListItemCollection items = list.GetItems(query);
ctx.Load(items);
ctx.ExecuteQuery();

foreach (var item in items)
{
Console.WriteLine("Item id: "+ item.Id);
var folder = item.Folder;
ctx.Load(folder);
var ds = Microsoft.SharePoint.Client.DocumentSet.DocumentSet.GetDocumentSet(ctx, folder);
ctx.Load(ds);
var dsVersions = ds.VersionCollection;
ctx.Load(dsVersions);
ctx.ExecuteQuery();
Console.WriteLine("Version count: "+ dsVersions.Count);
}

 

 

 

To add a new version aka capture version of a document set:

 

 

 

//Add new version. First parameter signifies whether to capture items within docset with their major or minor versions checked in. Second parameter is a string/comment.

dsVersions.Add(true, "capture new version thru CSOM");

//To get contents of a captured version of a Document set along with the site columns (fields) for the library.

List<Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionItem> itemsWithinDS = (List<Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionItem>)dsVersions[0].GetDisplayContents();

List<Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionField> fields = (List<Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionField>)dsVersions[0].GetDisplayFields();

ctx.ExecuteQuery();
Console.WriteLine("Contents count: " + itemsWithinDS.Count);
Console.WriteLine($"Field title: {fields[0].Title}, Value: {fields[0].FormattedValue}");

Do not forge to dispose of your ClientContext object :)

ctx.Dispose();

 

 

 

I also have the PowerShell script posted on my GitHub Gist account. It showcases how to get all Document Set items, capture versions, enumerate contents and the fields. Here is the full PowerShell script:

 

 

 

cls
#Import-Module Microsoft.Online.SharePoint.PowerShell
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.DocumentManagement.dll"

#Setting this to True will create new version for any DocSet it identifies that has zero versions existing
$CreateNewVersion = $true
$AdminPass = "password"
$AdminPassword = ConvertTo-SecureString -string $AdminPass -AsPlainText -Force
#$AdminPassword=Read-Host -Prompt "Enter password" -AsSecureString
$username="MeganB@YourTenant.OnMicrosoft.com"
$Url="https://YourTenant.sharepoint.com/sites/ModernTeamSite"
$ListTitle="Documents"
$ctx=New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $AdminPassword)
$ctx.Load($ctx.Web)
$ctx.ExecuteQuery()
$list=$ctx.Web.Lists.GetByTitle($ListTitle)
$ctx.Load($list)
$ctx.ExecuteQuery()
"Document Library: "+ $ListTitle
"Total Item Count: "+ $list.ItemCount

$spqQuery = New-Object Microsoft.SharePoint.Client.CamlQuery
$spqQuery.ViewXml = "<View><Query><Where><Eq><FieldRef Name='ContentType' /><Value Type='Computed'>Document Set</Value></Eq></Where></Query></View>";
#$spqQuery.v.ViewFields = "<FieldRef Name='FileLeafRef' /><FieldRef Name='Title' />"
#$spqQuery.ViewFieldsOnly = $true
$items = $list.GetItems($spqQuery)
$ctx.Load($items)
$ctx.ExecuteQuery()
write-host "Found (" $items.Count ") DocumentSet content type items."
write-host ""

foreach ($splListItem in $items)
{
    write-host "Id: " $splListItem.Id " ," "Title:" $splListItem["Title"] -ForegroundColor Green
    $folder = $splListItem.Folder;
    $ctx.Load($folder);
    $ctx.ExecuteQuery()
    $docSetItem = [Microsoft.SharePoint.Client.DocumentSet.DocumentSet]::GetDocumentSet($ctx, $folder)
    $ctx.Load($docSetItem)
    $ctx.ExecuteQuery()
    $docSetItemVersions = $docSetItem.VersionCollection
    $ctx.Load($docSetItemVersions)
    $ctx.ExecuteQuery()
    write-host "Total versions: " $docSetItemVersions.Count
   
    if($docSetItemVersions.Count -gt 0)
    {
        $docSetItemVersions | %{
            Write-Host "Fetching the version contents..." -ForegroundColor Yellow
            #$_ | Get-Member
            Write-Host "Version Id: "$_.VersionLabel ", Comment: " $_.Comments ", Created: " $_.Created ", By: " $_.CreatedBy
            #$versionContents = New-Object System.Collections.Generic.List[Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionItem]
            $versionContents = [System.Collections.Generic.List[Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionItem]]$_.GetDisplayContents();
            $fieldValues = [System.Collections.Generic.List[Microsoft.SharePoint.Client.DocumentSet.DocumentSetVersionField]]$_.GetDisplayFields();
            $ctx.ExecuteQuery()
            #Write-Host $versionContents[0]
            #$versionContents[0] | Get-Member
            write-host "Found (" $versionContents.Count ") items in this doc set verion:"
            $versionContents | %{ write-host "-- ItemUrl:" $_.ItemUrl ", VersionLabel:" $_.VersionLabel ", InternalId: " $_.InternalId}
            #$fieldValues.Count
            write-host "Field values found in this version:"
            $fieldValues | %{ Write-Host "-- Title: " $_.Title ", Value: "$_.FormattedValue }
            Write-Host ""
        }
    }
    else {
        $docSetItemVersions.Add($true, "v1")
        $ctx.ExecuteQuery()
    }
    write-host ""
    write-host ""
}
$ctx.Dispose()

 

 

 

Here is the official MS docs for Add method that captures the version. https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.documentmanagement.documentsets.documentsetversioncollection.add?view=sharepoint-server

 

Upcoming updates:

 

The Document Sets product group team is actively working on supporting Copy/Move functionality for Document Set content type items. Today the Copy/Move functionality works for Document Sets, but its scope is limited to within the document library. It doesn’t support copying/moving them across libraries or sites. With the upcoming update that’s going to change. Expect this update to roll out to all tenants in early September 2020.

 

Hope that helps!

 

 

 

Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.

Updated Sep 28, 2020
Version 5.0
  • Luca3082's avatar
    Luca3082
    Copper Contributor

    Hi, is it possible to do the same in SharePoint OnPremise (with CSOM)? I tried in our project but there is no VersionCollection in the Microsoft.SharePoint.Client.DocumentSet library.

    Thanks

     

  • Hi - and thanks for the article.

    I need to do the same thing but from JavaScript. When using JSOM instead of CSOM, I only have access to one method on DocumentSet.DocumentSet: the "create" method. 

    There is no "get" method, and therefor no way to get the versions or invoke the "add" method to create a new version.

    Do you have any ideas on how to get access to the methods, or is there something else that I overlook?

     

    Regards

    Leif

     

    -----------------------------------

    I have now found the answer: You can use the Graph API to accomplish this:

    https://graph.microsoft.com/v1.0/sites/{site id}/lists/{list}/items/3/documentSetVersions

     

    POST this to the endpoint to create the version snapshot:

    {
        "comment": "Some comment for the version",
        "shouldCaptureMinorVersion": false
    }
  • Leif Frederiksen I was asked this question even before and unfortunately, I was not able to get an answer. I recommend opening a support case to get an official answer from MS support. 

    Sorry, couldn't be of much help here. I moved to a new role and not actively working on SharePoint.