Download documents from a SharePoint site or web

We often get the request to download all documents from SharePoint to the file share. We mostly see these kinds of questions when customers are cleaning up their environment, preparing to quit with SharePoint or just backing up their documents without the use of ootb or third party tools. I have written the below script to export all documents from a specific web. This script will loop through all the document libraries from the specified web and will also download the libraries from sub-webs. You can copy this script to a PowerShell file and follow the below manual for using this script.

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction "silentlycontinue"

$exportPath = Read-Host "Enter the export location (eg. C:\export). This directory will be created if it doesn’t exist"
$URL = Read-Host "Enter the url from SharePoint (eg. <a href="https://portal.sharepointfire.com">https://portal.sharepointfire.com</a>). This needs to be a site collection or web"

function downloadFiles($OutputLocation, $url){
#Create output folders
$rootFolder = createFolder ($OutputLocation + "\Output")
$errorFolder = createFolder ($rootFolder + "\Errors")

#Create logging files
$loggingFile = createFile ($rootFolder + "\logging.csv")
$notDownloadedFile = createFile ($rootFolder + "\notDownloaded.csv")
$errorFile = createFile ($rootFolder + "\errors.csv")

#Verify that the URL is a web in SharePoint
try{
$web = get-spweb $url -erroraction "silentlycontinue"
$web.dispose()
write-host "Update: Starting downloading specified web" -foregroundcolor green

#Start download of specified url
downloadWeb $url $rootFolder
}
catch{
write-host "Error: URL is not a valid web in SharePoint" -foregroundcolor red
}
}

function createFolder($folderPath){
#Create directory
#first test if the directory is not longer then 248 characters.
$count = $folderPath | measure-object -character

if ($count.characters -le 247){
#verify if the parth exists
if (!(Test-Path -path $folderPath)){
New-Item $folderPath -type directory | out-null
write-host "Folder created: $($folderPath)" -foregroundcolor green
}
else{
write-host "Folder already exists, trying to create a unique folder with random number" -foregroundcolor yellow

#create a random to add to the folder name because it already exists
$randomNumber = Get-Random -minimum 1 -maximum 10
if ((Test-Path -path $errorFile) -eq $true){
add-content -value "Folder: $($folderPath) already exists and created a unique folder with number $($randomNumber)" -path $errorFile
}

$folderPath = createFolder ($folderPath + $randomNumber)
}
}
else{
#create a folder under errors to download the files to
write-host "Foldername is to long, trying to create a folder under the errors folder" -foregroundcolor yellow
if ((Test-Path -path $errorFile) -eq $true){
add-content -value "Folder: $($folderPath) is to long and documents have been moved to the error folder under $SPWeb.Title" -path $errorFile
}

$folderpath = $errorFolder + "\site-" + $SPWeb.Title
New-Item $folderPath -type directory | out-null
}
return $folderPath
}

function createFile($filePath){
#Create file
if (!(Test-Path -path $filePath)){
New-Item $filePath -type file | out-null
write-host "File created: $($filePath)" -foregroundcolor green
}
else{
#add a number to the file name if it already exists
write-host "File already exists, trying to create a unique folder with random number" -foregroundcolor yellow
$randomNumber = Get-Random -minimum 1 -maximum 100
add-content -value "File: $($filePath) already exists and created a unique file with number $($randomNumber)" -path $errorFile
$filePath = createFile ($filePath + $randomNumber)
}
return $filePath
}

function downloadWeb($startWeb, $rootFolder){
#Get web information with PowerShell
$SPWeb = get-spweb "$startWeb"

#Store the full sitefolder url in a variable and create the folder
$siteFolder = createFolder ($rootFolder + "\site-" + $SPweb.Title)

#Store the full url in a text file inside the folder
$SPWeb.url | out-file -filepath $siteFolder\siteURL.txt

#Loop through all the document libraries
foreach($list in $SPweb.lists){
if($list.BaseType -eq "DocumentLibrary"){
#Get root folder
$listUrl = $web.Url +"/"+ $list.RootFolder.Url
#Download root files
downloadLibrary $list.RootFolder.Url
#Download files in folders
foreach ($folder in $list.Folders){
downloadLibrary $folder.Url
}
}
}

#add logging to show which webs have been touched
add-content -value "Downloaded: $($SPWeb.url)" -path $loggingFile

#Loop through each subsite of the web
$SPWebs = $SPWeb.webs
foreach($SPweb in $SPwebs){
downloadWeb $SPweb.url $siteFolder
}

#dispose web
$SPWeb.dispose()
}

function downloadLibrary ($libraryURL){
#Create folder based on document library name
$SPLibrary = $SPWeb.GetFolder($libraryURL)
$libraryFolder = createFolder ($siteFolder + "\lib-" + $SPLibrary.url)
Write-Host "Downloading library: $($SPLibrary.name)" -foreground darkgreen
add-content -value "Downloading library: $($SPLibrary.name)" -path $loggingFile

foreach ($file in $SPLibrary.Files){
#Download file
try{
$binary = $file.OpenBinary()
$stream = New-Object System.IO.FileStream($libraryFolder + "\" + $file.Name), Create
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.write($binary)
$writer.Close()
}
catch{
write-host "File: $($file.Name) error" -foregroundcolor red
add-content -value "File: $($SPWeb.url) has not been downloaded" -path $notDownloadedFile
}
}
}

downloadFiles -OutputLocation $exportPath -url $url 

Manual created with SharePoint 2016

First run PowerShell as administrator

image

next load the PowerShell script

image

Enter the export location (eg. C:\export). This directory will be created if it doesn’t exist

image

Enter the url from SharePoint (eg. https://portal.sharepointfire.com). This needs to be a site collection or web in SharePoint. press enter to start downloading

image

This script will first create the output libraries and logging files and will then start to download all document libraries. Note that this also means that master page gallery’s and site pages will be downloaded. You can create your own filter if needed.

The output will look like this

image

image

image

and the logfile as follows:

image

Please let me know if you receive any errors or you have tips on making this script better.

2 thoughts on “Download documents from a SharePoint site or web

    • Hi Joe,

      I believe it’s not possible to maintain the created/modified dates of the files @ the document level. You can always create a .CSV file where you can store all metadata from a document library and you can refer to this .CSV when you need the information.

      It is possible to pull the versions of each file. I suggest to create an additional function which you can call after

      $binary = $file.OpenBinary()
      $stream = New-Object System.IO.FileStream($libraryFolder + “\” + $file.Name), Create
      $writer = New-Object System.IO.BinaryWriter($stream)
      $writer.write($binary)
      $writer.Close()

      You will then need to loop through all versions using $file.versions and use the following to download the versions:

      $webclient = New-Object System.Net.WebClient
      $webClient.UseDefaultCredentials = $true
      $webclient.DownloadFile($fileURL,$DownloadPath)

      you can find $fileURL using $webUrl + “/” + $version.Url and $DownloadPath is $libraryFolder + “/” + “FileName” + $version.versionlabel + “extension”.

      I will add this functionality to this script when I have some more time.

      Please let me know if you have any more questions,
      Kind regards,
      Maarten

Leave a Reply

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