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 (and download files in it!) from SharePoint Online.

Assuming you have read permissions at least, follow these steps to download a folder from SharePoint Online:

  1. Login to your SharePoint Online Site collection, and Navigate to the SharePoint document library or the parent folder where the Folder you want to download exists.
  2. Right-click on the Folder  >> Choose “Download” from the context menu. You can also use the “Download” button from the toolbar.
  3. 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 -foregroundcolor 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

How do I download a folder from SharePoint using PowerShell? Well, this PnP PowerShell script downloads all files and sub-folders from the specific 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 Sourcefile
    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" #TargetFilePath
 
#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)'"
}

To download all files and folders from a SharePoint Online document library, use: PowerShell to download all files from SharePoint Online Library

How do I download a file from SharePoint using PnP PowerShell?

Use the PnP PowerShell cmdlet “Get-PnPFile” to download a file from SharePoint Online.
More info: PowerShell to download a file from SharePoint Online

How do I upload files and folders to SharePoint Online?

To upload a folder along with its files, use Upload folder to SharePoint Online using PowerShell

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!

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

  • I think it’s worth noting that in SharePoint Online our URLs had %20 representing spaces. The script can’t resolve a line that has those (at least for us). Replace with space and works fine.

    Reply
  • Hello. I am receiving the same as Noel. I run the script. It appears to run successfully, but I get nothing in the specified folder. For clarity, I am trying to download a folder several spots below the document library. I am trying get from Document Library/first level/second level/third level. I want to download the third level folder and all folders under it.

    1. Will your script do this?
    2. Why am I not getting any files while running the script?

    Thanks for any updates.

    Reply
    • I just tried the last script in the post and confirmed it just works fine. Does it give any message like:
      “Ensured Folder ‘C:\Docs\….’
      Downloaded File from ‘/sites/Retail/Shared Documents/2019/Active/invoice.xlsx'”.
      Are you running with the PnP.PowerShell module? Not the legacy SharePointPnPPowerShellOnline!

      Reply
  • 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. Required fields are marked *