How to Download a Folder from SharePoint Online using PowerShell?

Requirement: Download a Folder from SharePoint Online

How to Download a Folder from SharePoint Online?

Are you wondering how to download a folder from SharePoint Online? Well, this post will show you how! In just a few easy steps, you can have the contents of a SharePoint folder on your computer. In this blog post, we will show you how to download a folder from SharePoint Online.

Follow these steps to download a folder from SharePoint Online:

  • Login to your SharePoint Online Site, Navigate to the Folder you want to download.
  • Right-click on the Folder  >> Choose “Download” from the context menu. You can also use the “Download” button from the toolbar.
  • This brings you a Zip file with the Selected folder and its Sub-Folders and its files.
    powershell download folder from sharepoint online

    Simple, huh? You can now finally get your hands on all of those documents right in front of you without having to open another tab on your browser.

    Let’s see how to download a SharePoint Online folder using PowerShell.

SharePoint Online: Download Folder using PowerShell

Now, when we need to download a folder repeatedly or automatically on a scheduled basis, we can utilize PowerShell. Here is my PowerShell to download a folder from SharePoint Online:

#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 Download-SPOFolder()
{ 
    param
    (
        [Parameter(Mandatory=$true)] [string] $SiteURL,
        [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.Folder] $SourceFolder,
        [Parameter(Mandatory=$true)] [string] $TargetFolder
    )
    Try {
         
        #Create Local Folder, if it doesn't exist
        $FolderName = ($SourceFolder.ServerRelativeURL) -replace "/","\"
        $LocalFolder = $TargetFolder + $FolderName
        If (!(Test-Path -Path $LocalFolder)) {
                New-Item -ItemType Directory -Path $LocalFolder | Out-Null
        }
         
        #Get all Files from the folder
        $FilesColl = $SourceFolder.Files
        $Ctx.Load($FilesColl)
        $Ctx.ExecuteQuery()
 
        #Iterate through each file and download
        Foreach($File in $FilesColl)
        {
            $TargetFile = $LocalFolder+"\"+$File.Name
            #Download the file
            $FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($Ctx,$File.ServerRelativeURL)
            $WriteStream = [System.IO.File]::Open($TargetFile,[System.IO.FileMode]::Create)
            $FileInfo.Stream.CopyTo($WriteStream)
            $WriteStream.Close()
            write-host -f Green "Downloaded File:"$TargetFile
        }
         
        #Process Sub Folders
        $SubFolders = $SourceFolder.Folders
        $Ctx.Load($SubFolders)
        $Ctx.ExecuteQuery()
        Foreach($Folder in $SubFolders)
        {
            If($Folder.Name -ne "Forms")
            {
                #Call the function recursively
                Download-SPOFolder -SiteURL $SiteURL -SourceFolder $Folder -TargetFolder $TargetFolder
            }
        }
     }
    Catch {
        write-host -f Red "Error Downloading Folder!" $_.Exception.Message
    }
}
 
#Set parameter values
$SiteURL="https://crescent.sharepoint.com"
$FolderRelativeUrl ="Shared Documents/Reports"
$TargetFolder="C:\Docs"
 
#Setup Credentials to connect
$Cred= Get-Credential
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
 
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Credentials

#Get the Web
$Web = $Ctx.Web
$Ctx.Load($Web)
$Ctx.ExecuteQuery()
$Web.ServerRelativeUrl+$FolderRelativeUrl
      
#Get the Folder
$SourceFolder = $Web.GetFolderByServerRelativeUrl($Web.ServerRelativeUrl+$FolderRelativeUrl)
$Ctx.Load($SourceFolder)
$Ctx.ExecuteQuery()

#Call the function to download a Folder
Download-SPOFolder -SiteURL $SiteURL -SourceFolder $SourceFolder -TargetFolder $TargetFolder 

PnP PowerShell to Download a Folder from SharePoint Online

This PowerShell script downloads all files and sub-folders from the given Folder in the SharePoint Online document library to a local directory.

#Function to Download All Files from a SharePoint Online Folder - Recursively  
Function Download-SPOFolder([Microsoft.SharePoint.Client.Folder]$Folder, $DestinationFolder)
{  
    #Get the Folder's Site Relative URL
    $FolderURL = $Folder.ServerRelativeUrl.Substring($Folder.Context.Web.ServerRelativeUrl.Length)
    $LocalFolder = $DestinationFolder + ($FolderURL -replace "/","\")
    #Create Local Folder, if it doesn't exist
    If (!(Test-Path -Path $LocalFolder)) {
            New-Item -ItemType Directory -Path $LocalFolder | Out-Null
            Write-host -f Yellow "Created a New Folder '$LocalFolder'"
    }
           
    #Get all Files from the folder
    $FilesColl = Get-PnPFolderItem -FolderSiteRelativeUrl $FolderURL -ItemType File 
    #Iterate through each file and download
    Foreach($File in $FilesColl)
    {
        Get-PnPFile -ServerRelativeUrl $File.ServerRelativeUrl -Path $LocalFolder -FileName $File.Name -AsFile -force
        Write-host -f Green "`tDownloaded File from '$($File.ServerRelativeUrl)'"
    }
    #Get Subfolders of the Folder and call the function recursively
    $SubFolders = Get-PnPFolderItem -FolderSiteRelativeUrl $FolderURL -ItemType Folder
    Foreach ($Folder in $SubFolders | Where {$_.Name -ne "Forms"})
    {
        Download-SPOFolder $Folder $DestinationFolder
    }
}  
 
#Set Parameters
$SiteURL = "https://crescent.sharepoint.com/sites/marketing"
$FolderSiteRelativeURL = "/Team Documents/2018"
$DownloadPath ="C:\Docs"
 
#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -Interactive
 
#Get the folder to download
$Folder = Get-PnPFolder -Url $FolderSiteRelativeURL
 
#Call the function to download all files from a folder
Download-SPOFolder $Folder $DownloadPath

Download a Folder with its Subfolders and Files from a Larger Document Libraries

While the above scripts work perfectly fine, We may encounter Listview threshold exceeded issues on larger libraries. To mitigate that issue, Here is my alternate script that downloads files from a SharePoint Online folder to the local disk:

#Set Parameters
$SiteURL = "https://Crescent.sharepoint.com/sites/marketing"
$FolderServerRelativeURL = "/Sites/Marketing/Shared Documents/New"
$DownloadPath ="C:\Docs\New"
  
#Connect to PnP Online
Connect-PnPOnline -Url $SiteURL -Interactive
$Web = Get-PnPWeb

#Get the Folder to download
$Folder = Get-PnPFolder -Url $FolderServerRelativeURL -Includes ListItemAllFields.ParentList
#Get the Folder's Site Relative URL
$FolderSiteRelativeURL = $FolderServerRelativeUrl.Substring($Web.ServerRelativeUrl.Length)

$List = $Folder.ListItemAllFields.ParentList
#Get all Folders from List - with progress bar
$global:counter = 0;
$ListItems = Get-PnPListItem -List $List -PageSize 500 -Fields FileLeafRef -ScriptBlock { Param($items) $global:counter += $items.Count; Write-Progress -PercentComplete `
                ($global:Counter / ($List.ItemCount) * 100) -Activity "Getting Items from List:" -Status "Processing Items $global:Counter to $($List.ItemCount)";} | Where {$_.FieldValues.FileRef -like "$($FolderServerRelativeUrl)*"} 
Write-Progress -Activity "Completed Retrieving Items from Folder $FolderServerRelativeURL" -Completed

#Get Subfolders of the Folder
$SubFolders = $ListItems | Where {$_.FileSystemObjectType -eq "Folder" -and $_.FieldValues.FileLeafRef -ne "Forms"}
$SubFolders | ForEach-Object {
    #Ensure All Folders in the Local Path
    $LocalFolder = $DownloadPath + ($_.FieldValues.FileRef.Substring($Web.ServerRelativeUrl.Length)) -replace "/","\"
    #Create Local Folder, if it doesn't exist
    If (!(Test-Path -Path $LocalFolder)) {
            New-Item -ItemType Directory -Path $LocalFolder | Out-Null
    }
    Write-host -f Yellow "Ensured Folder '$LocalFolder'"
}
#Get all Files from the folder
$FilesColl =  $ListItems | Where {$_.FileSystemObjectType -eq "File"}
#Iterate through each file and download
$FilesColl | ForEach-Object {
    $FileDownloadPath = ($DownloadPath + ($_.FieldValues.FileRef.Substring($Web.ServerRelativeUrl.Length)) -replace "/","\").Replace($_.FieldValues.FileLeafRef,'')
    Get-PnPFile -ServerRelativeUrl $_.FieldValues.FileRef -Path $FileDownloadPath -FileName $_.FieldValues.FileLeafRef -AsFile -force
    Write-host -f Green "Downloaded File from '$($_.FieldValues.FileRef)'"
}

Salaudeen Rajack

Salaudeen Rajack - SharePoint Expert with Two decades of SharePoint Experience. Love to Share my knowledge and experience with the SharePoint community, through real-time articles!

8 thoughts on “How to Download a Folder from SharePoint Online using PowerShell?

  • Hi Salaudeen, I just tried using the script titled “Download a Folder with its Subfolders and Files from a Larger Document Libraries”, and the script appears to complete successfully (blue bar reaches the end, etc.), but the files are not transferred to my computer. There are no errors. Do you have any suggestions? Thanks!

    Reply
    • That’s odd! Are you sure you don’t find anything inside the folder you set for $TargetFolder or $DownloadPath parameters?

      Reply
  • Trying to download data about 100GB from SPO but we get an error after few hour
    Error Downloading Folder! Exception calling “OpenBinaryDirect” with “2” argument(s): “The operation has timed out”
    Error Downloading Folder! Exception calling “ExecuteQuery” with “0” argument(s): “The operation has timed out”

    Reply
  • Download-SPOFolder : Cannot process argument transformation on parameter ‘Folder’. Cannot convert the “Microsoft.SharePoint.Client.Folder” value of type “Microsoft.SharePoint.Client.Folder” to type “Microsoft.SharePoint.Client.Folder”.
    At line:1 char:20
    + Download-SPOFolder $Folder $DownloadPath
    + ~~~~~~~
    + CategoryInfo : InvalidData: (:) [Download-SPOFolder], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Download-SPOFolder

    Reply
    • Just close and Re-Open the PowerShell ISE. That should do the Magic.

      Reply
  • This script is almost perfect for me, but I have a large list and it fails on a folder that exceeds the threshold. Is there anyway to batch up the download of the files in a large folder?

    Reply
      • Is it possible for this to work on a root folder? E.g. /Sites/Marketing/Shared Documents instead of /Sites/Marketing/Shared Documents/New?

        It gives error “The property or field ‘Title’ has not been initialized.”, I believe as a result of line 11 “ListItemAllFields.ParentList”

        Reply

Leave a Reply

Your email address will not be published.