Skip to content

Instantly share code, notes, and snippets.

@RylandDeGregory
Last active January 28, 2024 00:35
Show Gist options
  • Save RylandDeGregory/f911cf0c37fdf0b5932d4b32c0c7b008 to your computer and use it in GitHub Desktop.
Save RylandDeGregory/f911cf0c37fdf0b5932d4b32c0c7b008 to your computer and use it in GitHub Desktop.
Recursively download all files from a SharePoint Document Library folder using the Microsoft Graph PowerShell SDK.
<#
.SYNOPSIS
This script will download all files from a specified SharePoint Document Library path.
.EXAMPLE
$ScriptParams = @{
SharePointTenant = 'mycompany.sharepoint.com'
SiteName = 'mysite/my subsite'
DocumentLibraryName = 'Documents'
DocumentLibraryPath = 'my directory/my subdirectory'
LastModifiedDate = (Get-Date '2024-01-01')
}
Start-MgSPOLibraryDownload @ScriptParams
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$SharePointTenant,
[Parameter(Mandatory)]
[string]$SiteName,
[Parameter(Mandatory)]
[string]$DocumentLibraryName,
[Parameter(Mandatory)]
[string]$DocumentLibraryPath,
# Only process files modified after this date
[Parameter()]
[datetime]$LastModifiedDate
)
#region Init
$ErrorActionPreference = 'Stop'
# Define the base URL for Microsoft Graph API
$GraphEndpoint = 'https://graph.microsoft.com/v1.0'
# Define SharePoint details
$DocumentLibraryFullPath = "$SiteName/$DocumentLibraryName/$DocumentLibraryPath"
#endregion Init
#region Login
try {
# Connect to Microsoft Graph with the required API Scope
Write-Output 'Connect to Microsoft Graph'
Connect-MgGraph -Scopes 'Sites.Read.All' -NoWelcome
} catch {
Write-Error "Failed to connect to Microsoft Graph: $_"
}
#endregion Login
# region Functions
function Get-SPODriveItemsRecursively {
param(
[Parameter(Mandatory)]
[string] $GraphEndpoint,
[Parameter(Mandatory)]
[string]$FolderId,
[Parameter(Mandatory)]
[string]$DriveId
)
try {
# Get the child items of the specified folder
Write-Verbose "Getting child items of folder [$FolderId]"
$DriveItems = Invoke-MgGraphRequest -Method GET -Uri "$GraphEndpoint/drives/$DriveId/items/$FolderId/children"
} catch {
Write-Error "Failed to get child items in folder [$FolderId]: $_"
}
foreach ($Item in $DriveItems.value) {
if ($Item.folder) {
# Recursively get the children of the folder
Get-SPODriveItemsRecursively -GraphEndpoint $GraphEndpoint -FolderId $Item.id -DriveId $DriveId
} else {
$Item
}
}
}
#endregion Functions
#region GetDriveId
try {
# Get SharePoint site details
Write-Output "Get SharePoint site [$SharePointTenant/$SiteName] details"
$Site = Invoke-MgGraphRequest -Method GET -Uri "$GraphEndpoint/sites/$SharePointTenant`:/sites/$SiteName"
} catch {
Write-Error "Failed to get SharePoint site [$SharePointTenant/$SiteName] details using Microsoft Graph: $_"
}
# Extract the Site ID and SubSite ID from the Site details
$SiteId = $Site.id.Split(',')[1]
$SubSiteId = $Site.id.Split(',')[2]
try {
# Get the Drives (Document Libraries) in the Site
Write-Output "Get a list of Document Libraries in SharePoint site [$SiteName]"
$SiteDrives = Invoke-MgGraphRequest -Method GET -Uri "$GraphEndpoint/sites/$SiteId/sites/$SubSiteId/drives"
} catch {
Write-Error "Failed to get a list of Document Libraries in SharePoint site [$SiteName]: $_"
}
# Find the Drive ID of the specified Document Library
$DriveId = $SiteDrives.value | Where-Object { $_.name -eq $DocumentLibraryName } | Select-Object -ExpandProperty Id
#endregion GetDriveId
#region GetSharePointItems
try {
# Get the details of the specified path in the Document Library
Write-Output "Get the Item ID of the Document Library path [$DocumentLibraryFullPath]"
$DocumentLibraryPathId = Invoke-MgGraphRequest -Method GET -Uri "$GraphEndpoint/drives/$DriveId/root:/$DocumentLibraryPath" | Select-Object -ExpandProperty Id
} catch {
Write-Error "Failed to get the Item ID of the Document Library path [$DocumentLibraryFullPath]: $_"
}
# Recursively get all items in the specified Document Library path
Write-Output "Recursively retrieve all items in the SharePoint Document Library path [$DocumentLibraryFullPath]"
$DocumentLibraryPathItems = Get-SPODriveItemsRecursively -GraphEndpoint $GraphEndpoint -FolderId $DocumentLibraryPathId -DriveId $DriveId
# Filter folders out of the list of items to process
$DocumentLibraryFiles = $DocumentLibraryPathItems | Where-Object { $_.file }
# Filter files based on LastModifiedDateTime if a cutoff date is provided
if ($LastModifiedDate) {
$DocumentLibraryFiles = $DocumentLibraryFiles | Where-Object { $_.lastModifiedDateTime -gt $LastModifiedDate }
}
Write-Output "Processing [$($DocumentLibraryFiles.Count)] files in the SharePoint Document Library path [$DocumentLibraryFullPath]"
#endregion GetSharePointItems
#region DownloadFiles
$CompletedFiles = 0
foreach ($DocumentLibraryFile in $DocumentLibraryFiles) {
# Parse SharePoint Document Library path
$SharePointFilePath = $DocumentLibraryFile.parentReference.path.split('/root:/')[1]
# Define local path for the file
$LocalPath = "$($env:TEMP)\$($DocumentLibraryFile.id)_$($DocumentLibraryFile.name)"
Write-Output "Processing [$([math]::Round($DocumentLibraryFile.Size / 1kb, 2)) KB] file [$($DocumentLibraryFile.name) ($($DocumentLibraryFile.id))]"
try {
# Download file from SharePoint
Invoke-RestMethod -Uri $DocumentLibraryFile.'@microsoft.graph.downloadUrl' -OutFile $LocalPath -ProgressAction SilentlyContinue
$CompletedFiles++
} catch {
Write-Warning "Failed to download file [$SharePointFilePath/$($DocumentLibraryFile.name) ($($DocumentLibraryFile.id))] from SharePoint Online: $_"
}
}
#endregion DownloadFiles
Write-Output "Complete. Downloaded [$CompletedFiles] files from SharePoint Online."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment