Using SharePoint Online CSOM to Capture Versions of Document Sets

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 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(“Document Set”)

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 itemsWithinDS = (List)dsVersions[0].GetDisplayContents();

List fields = (List)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 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 = “Document Set”;
#$spqQuery.v.ViewFields = “
#$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!

The sample are not supported under any Microsoft standard support program or service. The sample 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 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.


This article was originally published by Microsoft’s System Center Configuration Manager Blog. You can find the original article here.