SharePoint Online: Export List Version History to Excel using PowerShell

Requirement: Export all versions of SharePoint Online List Items to CSV (Excel) file.

sharepoint online export list version history to excel using powershell

PowerShell to Extract and Export List Item’s Version History to CSV File

As an administrator, there may be occasions when you need to export a SharePoint Online list version history to Excel for further analysis. We can export the list version history to Excel using PowerShell. This article assumes you have an existing SharePoint Online list with columns given below, and you may have to create and change columns according to your requirements. This article will walk you through the steps to export the SharePoint Online list version history to Excel using PowerShell.

#Load SharePoint CSOM Assemblies
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"

Function Export-VersionHistory()
{
  param
    (
        [Parameter(Mandatory=$true)] [string] $SiteURL,
        [Parameter(Mandatory=$true)] [string] $ListName,
        [Parameter(Mandatory=$true)] [string] $CSVFile
    )
    Try {

        #Delete the Output report file if exists
        if (Test-Path $CSVFile) { Remove-Item $CSVFile }

        #Get Credentials to connect
        $Cred= Get-Credential

        #Setup the context
        $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
        $Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
        
        #Get the List
        $List = $Ctx.Web.Lists.GetByTitle($ListName)
        $Ctx.Load($List)
        $Ctx.ExecuteQuery()
        
        #Define Query to get List Items in batch
        $Query = New-Object Microsoft.SharePoint.Client.CamlQuery
        $Query.ViewXml = "<View Scope='RecursiveAll'><RowLimit>2000</RowLimit></View>"
  
        #Batch process list items - to mitigate list threshold issue on larger lists
        Do {  
            #Get items from the list in batches
            $ListItems = $List.GetItems($Query)
            $Ctx.Load($ListItems)
            $Ctx.ExecuteQuery()            
            $Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition

            #Array to hold result
            $VersionHistoryData = @()

            #Iterate throgh each item
            Foreach ($Item in $ListItems)
            {
                write-host "Processing Item:" $item.id -f Yellow
            
                #Get all versions of the list item
                $Versions = $Item.versions
                $ctx.Load($Versions)
                $Ctx.ExecuteQuery()

                If($Versions.count -gt 0)
                {
                    #Iterate each version
                    Foreach($Version in $Versions)
                    {
                        #Get the Creator object of the version
                        $CreatedBy =  $Version.createdby
                        $Ctx.Load($CreatedBy)
                        $Ctx.ExecuteQuery()

                        #Send Data to object array
                        $VersionHistoryData += New-Object PSObject -Property @{
                        'Item ID' = $Item.ID
                        'Title' =  $Version.FieldValues["Title"]
                        'Version Label' = $Version.VersionLabel 
                        'Version ID' = ($Version.VersionId/512)
                        'Created On' = (Get-Date ($Version.Created) -Format "yyyy-MM-dd/HH:mm:ss")
                        'Created By' = $CreatedBy.Email
                        }
                    }
                }
            }
        }While($Query.ListItemCollectionPosition -ne $null)
        #Export the data to CSV
        $VersionHistoryData | Export-Csv $CSVFile -Append -NoTypeInformation

        Write-host -f Green "Version History Exported Successfully to:" $CSVFile
     }
    Catch {
        write-host -f Red "Error Exporting version History to CSV!" $_.Exception.Message
    }
}

#Set parameter values
$SiteURL="https://crescent.sharepoint.com"
$ListName="Projects"
$CSVFile="C:\Temp\VersionHistory.csv"

#Call the function to generate version History Report
Export-VersionHistory -SiteURL $SiteURL -ListName $ListName -CSVFile $CSVFile

I have used the “Title” field value in the script. You can add any other columns with: $version.FieldValues[“ColumnInternalName”]

Important: This script works ONLY on CSOM version 16.1.6906.1200 or Later! Download the latest version of CSOM SDK from https://www.microsoft.com/en-us/download/confirmation.aspx?id=42038

This script produces a CSV file with version data such as:

  • Version Label,
  • Version ID
  • When the version was created
  • Who created the version
  • Title field value of the version (You can add any additional field too!)

For SharePoint On-Premises, use this script: How to Export SharePoint Version History to CSV using PowerShell?

PnP PowerShell to Export Version History of All Items in a List

Let’s export all previous versions of items from a list to a CSV file using PnP PowerShell.

#Set Variables
$SiteURL = "https://crescent.sharepoint.com/sites/PMO"
$ListName = "Projects"
$CSVPath = "C:\Temp\ProjectsVersionsRpt.csv"
  
#Connect to SharePoint Online site
Connect-PnPOnline -Url $SiteURL -Interactive
 
#Get All Fields from List
$ListFields = Get-PnPField -List $ListName | Where {!$_.Hidden}
$VersionHistoryData = @()
 
#Get All List Items - Exclude Folders
Get-PnPListItem -List $ListName -PageSize 500 | Where {$_.FileSystemObjectType -ne "Folder"} | ForEach-Object {
    Write-host "Getting Versioning Data of Item:"$_.ID
    $Versions = Get-PnPProperty -ClientObject $_ -Property Versions
    ForEach($Version in $Versions)
    {
        $VersionHistory =  New-Object PSObject
        $VersionHistory | Add-Member -MemberType NoteProperty -Name "Version ID" -Value ($Version.VersionId/512)
        $VersionHistory | Add-Member -MemberType NoteProperty -Name "Version Label" -Value $Version.VersionLabel
        $VersionHistory | Add-Member -MemberType NoteProperty -Name "Created On" -Value (Get-Date ($Version.Created) -Format "yyyy-MM-dd/HH:mm:ss")
 
        #Get Value of all other Fields
        $ListFields | ForEach-Object {            
            #Handle Special Fields
            $FieldType  = $_.TypeAsString 
            If($FieldType -eq "User" -or $FieldType -eq "UserMulti" -or $FieldType -eq "Lookup" -or $FieldType -eq "LookupMulti")
            {
                $FieldValue = $Version[$_.InternalName].LookupValue -join "; "
            }
            ElseIf($FieldType -eq "URL") #Hyperlink
            {
                $URL = $Version[$_.InternalName].URL
                $Description  = $Version[$_.InternalName].Description
                $FieldValue = "$URL, $Description"
            }
            ElseIf($FieldType -eq "TaxonomyFieldType" -or $FieldType -eq "TaxonomyFieldTypeMulti") #MMS
            {
                $FieldValue = $Version[$_.InternalName].Label -join "; "
            }
            Else
            {
                #Get Source Field Value
                $FieldValue = $Version[$_.InternalName]
            }
            #Append Version data
            $VersionHistory | Add-Member -MemberType NoteProperty -Name $_.InternalName -Value $FieldValue
        }
        $VersionHistoryData+=$VersionHistory
    }
}
$VersionHistoryData | Export-Csv $CSVPath -NoTypeInformation

Don’t forget to replace the variables SiteURL, ListName and CSVPath with the values relevant to your environment.

Salaudeen Rajack

Salaudeen Rajack - Information Technology Expert with Two-decades of hands-on experience, specializing in SharePoint, PowerShell, Microsoft 365, and related products. He has held various positions including SharePoint Architect, Administrator, Developer and consultant, has helped many organizations to implement and optimize SharePoint solutions. Known for his deep technical expertise, He's passionate about sharing the knowledge and insights to help others, through the real-world articles!

36 thoughts on “SharePoint Online: Export List Version History to Excel using PowerShell

  • Hello,
    For “PnP PowerShell to Export Version History of All Items in a List”, can we modify this script to do from a certain ID? I want to run this regularly, but the table is quite large, and I want to start from a specific record.

    Reply
  • hello, thanks for the script.
    I need help with modifying the script to export all items including versions into a CSV file.
    Script should target site collection, subsites, document libraries and exclude any SharePoint system libraries (i.e. master pages etc)
    thanks.

    Reply
  • Hi Salaudeen,

    Fantastic script!

    I have modified the script as per my requirements and its working perfectly fine for the projects with approx 100,000 files across libraries, But getting this below error randomly when i execute the script for projects with files more than 200,000 across different libraries. Saw this article of yours but I am not able to setup the context perfectly.
    https://www.sharepointdiary.com/2018/06/sharepoint-online-powershell-the-collection-has-not-been-initialized-error.html

    Issue1 : Getting an error “The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
    At line:21 char:13
    + ForEach($Version in $Versions)”
    ================================
    Issue2 : Is there a better way to observe if there are any failures or log the errors, I tried the start-transcript but its not working as expected and stops in between with error
    Getting Versioning Data of Item: 9874
    Stop-Transcript : An error occurred stopping transcription: The host is not currently transcribing.
    At line:64 char:1
    + Stop-Transcript
    + ~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [Stop-Transcript], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.StopTranscriptCommand

    Getting Versioning Data of Item: 3
    ================================
    Any help you provide would be highly appreciated.
    ================================
    #Set Variables
    $SiteURL = “https://tenant.sharepoint.com/sites/testsite”
    $AllLists = “Lib1,Lib2,Lib3,Lib4,Lib5”
    $ListName = $AllLists.Split(“,”)

    #Connect to SharePoint Online site
    Connect-PnPOnline -Url $SiteURL -UseWebLogin

    foreach($List in $ListName)
    {
    #Get All Fields from List
    $ListFields = Get-PnPField -List $List | Where {!$_.Hidden}
    $VersionHistoryData = @()

    #Get All List Items – Exclude Folders
    Get-PnPListItem -List $List -PageSize 500 | Where {$_.FileSystemObjectType -ne “Folder”} | ForEach-Object {
    Write-host “Getting Versioning Data of Item:”$_.ID
    $Versions = Get-PnPProperty -ClientObject $_ -Property Versions
    ForEach($Version in $Versions)
    {
    $VersionHistory = New-Object PSObject
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “Version ID” -Value ($Version.VersionId/512)
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “Sharepoint Library” -Value ($Version.FieldValues.FileDirRef)
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “File Path” -Value ($Version.FieldValues.FileRef)
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “FileName” -Value ($Version.FieldValues.FileLeafRef)
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “FileType” -Value ($Version.FieldValues.File_x0020_Type)
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “Version Label” -Value $Version.VersionLabel
    $VersionHistory | Add-Member -MemberType NoteProperty -Name “Created On” -Value (Get-Date ($Version.Created) -Format “yyyy-MM-dd/HH:mm:ss”)

    #Get Value of all other Fields
    $ListFields | ForEach-Object {
    #Handle Special Fields
    $FieldType = $_.TypeAsString
    If($FieldType -eq “User” -or $FieldType -eq “UserMulti” -or $FieldType -eq “Lookup” -or $FieldType -eq “LookupMulti”)
    {
    $FieldValue = $Version[$_.InternalName].LookupValue -join “; ”
    }
    ElseIf($FieldType -eq “URL”) #Hyperlink
    {
    $URL = $Version[$_.InternalName].URL
    $Description = $Version[$_.InternalName].Description
    $FieldValue = “$URL, $Description”
    }
    ElseIf($FieldType -eq “TaxonomyFieldType” -or $FieldType -eq “TaxonomyFieldTypeMulti”) #MMS
    {
    $FieldValue = $Version[$_.InternalName].Label -join “; ”
    }
    Else
    {
    #Get Source Field Value
    $FieldValue = $Version[$_.InternalName]
    }
    #Append Version data
    $VersionHistory | Add-Member -MemberType NoteProperty -Name $_.InternalName -Value $FieldValue
    }
    $VersionHistoryData+=$VersionHistory
    }
    }
    $VersionHistoryData | Export-Excel -WorksheetName “Version” “C:\Version\final\$($siteURL.split(“/”)[$siteURL.split(“/”).count-1])-docshare.xlsx” -Append
    }

    Reply
  • Awesome script! Thanks for sharing.

    How can these scripts be modified to include all Document Libraries? Maybe an ‘ExcludedLists’ can also be added to exclude some libraries.

    Reply
  • Hi,
    I’m trying to download the version history of a specific library from SharePoint online but due to MFA I’m getting an error of password does not match. I also tried creating Microsoft account password still the issue is persisting. Can you help me on how to deal with MFA?

    Reply
      • Does this still work? I tried using the CSOM version with app password but didn’t seem to authenticate properly.

        Reply
  • I have 5 MMS field but the it shows up as Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValue. Please suggest

    Reply
  • The PnP version of the script doesn’t show MMS term field. It comes as Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValue Please suggest.

    Reply
  • I am receiving following error. Version is enabled on the library.

    Processing Item: 357
    Error Exporting version History to CSV! Cannot find an overload for “Load” and the argument count: “1”.

    Reply
  • Hi How can I expand the URL property, its returning a system collection Microsoft.SharePoint.Client.FieldUrlValue

    Reply
    • You got to handle special fields like URL, MMS, etc. differently. E.g. To get the value of the Hyperlink field in SharePoint Online, use:

      $URL = $Item[$Field.InternalName].URL
      $Description  = $Item[$Field.InternalName].Description
      
      Reply
  • for the Sharepoint Management version, is there a way to pull all fields on the version history? I have multiple status’s and priorities that I need to measure changes to. Thanks!

    Reply
  • Hi Salaudeen. A fantastic script here. Just wondering, what would need to be added to include a particulars columns data from each version into the output csv?

    Reply
    • $Version[“FieldInternalName”] will get you the particular column’s value for the version!

      Reply
  • Hi there! am getting error: Add-Type : Cannot bind parameter ‘Path’ to the target. Exception setting “Path”: “Cannot find path… Any ideas on why? Thanks

    Reply
  • How can I limit the list by a date range? I am getting this error:
    Error Exporting version History to CSV! Exception calling “ExecuteQuery” with “0” argument(s): “The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.”

    Reply
    • Well, the script is updated now to handle larger lists ( >5000 Items) in batches to mitigate list view threshold issue.

      Reply
  • Script is working fine, but how to fetch last updated comments on list item ? is there any way ?

    Reply
  • Hi Salundeen,
    Mi name is Guille (from Spain).
    thank you for sharing your code and wisdom with all of us.

    I have a problem executing your code. Before I start, tell you what I’ve done or I am doing:
    – I have installed the latest version of the SDK (64 bits)
    – My SharePoint site is $SiteURL=”https://mycompany.sharepoint.com/sites/CursesSPO”.
    In this collection I created a list of tasks called MyTasks (whose URL is : https://mycompany.sharepoint.com/sites/CursesSPO/Lists/MyTasks
    ). Then my variable $ListName=”MyTasks”
    – I am using PowerShell ISE (as administrator). I copied your code into a .ps1 file and run it from PowerShell ISE itself.

    Well, when I execute an error appears (it is located in the first ExecuteQuery) that says:
    Error Exporting version History to CSV! Exception when calling “ExecuteQuery” with the arguments “0”: “The ‘MyTasks’ list does not exist on the site with the URL address ‘ht
    tps://mycompany.sharepoint.com/sites/CursesSPO’.”

    I can’t see why this is happening.
    Can you help me?

    Reply
    • One Quick hint: The URL of the List may be different from its Name! E.g., Your “https://mycompany.sharepoint.com/sites/CursesSPO/Lists/MyTasks” list may have its title as “My Task”. (watch the space between ‘My’ and ‘Task’)

      Reply
  • Thanks, your article helped me to solve my user request!

    Reply
  • Thank you, You are good among men!

    Reply
  • Do you think this script work for SharePoint 2010/13/2016 on-premise?

    Reply
  • Hi Salundeen,

    thanks for this great site. I’m in my first steps with PowerShell and have a question. What do I have to change in the script, so it can run on SharePoint 2010?

    Thanks

    Reply
  • Thanks Salaudeen for the detailed PS script. When I run the Powershell, I am getting ,Cannot find an overload for “Load” and the argument count: “1”‘

    Reply
    • Make sure you have the latest client SDK installed in your machine as per the link given in the post. Also, try running this in PowerShell ISE.

      Reply
    • Yes, I have installed the latest client SDK (32 Bit). I wanted this PS to run as a scheduled task and I am not sure how I can achieve that. My environment is O365.

      Reply
  • Hi,

    Thanks for this code a life saver. However, there is an error in your code. The $SiteURL = “…” is wrong you have a html hyperlink ref in there when in your case it should be $SiteURL = “https://crescent.sharepoint.com”.

    This caught me out for a few hours lol

    Reply
    • Hi There, $SiteURL=”https://crescent.sharepoint.com” is what I’ve posted. Let me know if this is not what you are getting!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *