This article is contributed. See the original author and article here.

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 = "";

SecureString password = ConvertToSecureString("secretpassword");

var ctx = new ClientContext("");

ctx.Credentials = new SharePointOnlineCredentials(userName, password);






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);



foreach (var item in items)


    Console.WriteLine("Item id: "+ item.Id);

    var folder = item.Folder;


    var ds = Microsoft.SharePoint.Client.DocumentSet.DocumentSet.GetDocumentSet(ctx, folder);


    var dsVersions = ds.VersionCollection;



    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();


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 :)




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:



#Import-Module Microsoft.Online.SharePoint.PowerShell

Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions16ISAPIMicrosoft.SharePoint.Client.dll"

Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions16ISAPIMicrosoft.SharePoint.Client.Runtime.dll"

Add-Type -Path "C:Program FilesCommon Filesmicrosoft sharedWeb Server Extensions16ISAPIMicrosoft.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




$ctx=New-Object Microsoft.SharePoint.Client.ClientContext($Url)

$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $AdminPassword)






"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)



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;



    $docSetItem = [Microsoft.SharePoint.Client.DocumentSet.DocumentSet]::GetDocumentSet($ctx, $folder)



    $docSetItemVersions = $docSetItem.VersionCollection



    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();


            #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}


            write-host "Field values found in this version:"

            $fieldValues | %{ Write-Host "-- Title: " $_.Title ", Value: "$_.FormattedValue }

            Write-Host ""



    else {

        $docSetItemVersions.Add($true, "v1")



    write-host ""

    write-host ""




Here is the official MS docs for Add method that captures the version.


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!

Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.