The Azure Storage platform is Microsoft’s cloud storage solution for modern data storage scenarios. Core storage services offer a massively scalable object store for data objects, disk storage for Azure virtual machines (VMs), a file system service for the cloud, a messaging store for reliable messaging, and a NoSQL store.

This PowerShell script shows how to download and sync documents in a SharePoint Document Library into an Azure Storage Container using CLI for Microsoft 365 and Azure CLI commands.


  • CLI for Microsoft 365
  • Azure CLI
  • SharePoint Online Site
  • Document Library with documents
  • Azure Storage Container
  • Azure Storage Account Key with required permission to upload documents

PowerShell Script

$spolHostName = ""
$spolSiteRelativeUrl = "/sites/site-name"
$spolDocLibTitle = "document-library-title"
$azStorageAccountKey = "*****************"
$azStorageAccountName = "azure-storage-account-name"
$azStorageContainerName = "azure-storage-container-name"
$localBaseFolderName = "local-base-folder-name"

$localFileDownloadFolderPath = $PSScriptRoot
$spolSiteUrl = $spolHostName + $spolSiteRelativeUrl

$spolLibItems = m365 spo listitem list --webUrl $spolSiteUrl --title $spolDocLibTitle --fields 'FileRef,FileLeafRef' --filter "FSObjType eq 0" -o json | ConvertFrom-Json

if ($spolLibItems.Count -gt 0) {

    ForEach ($spolLibItem in $spolLibItems) {

        $spolLibFileRelativeUrl = $spolLibItem.FileRef
        $spolFileName = $spolLibItem.FileLeafRef

        $spolLibFolderRelativeUrl = $spolLibFileRelativeUrl.Substring(0, $spolLibFileRelativeUrl.lastIndexOf('/'))

        $localDownloadFolderPath = Join-Path $localFileDownloadFolderPath $localBaseFolderName $spolLibFolderRelativeUrl

        If (!(test-path $localDownloadFolderPath)) {
            $message = "Target local folder $localDownloadFolderPath not exist"
            Write-Host $message -ForegroundColor Yellow

            New-Item -ItemType Directory -Force -Path $localDownloadFolderPath | Out-Null

            $message = "Created target local folder at $localDownloadFolderPath"
            Write-Host $message -ForegroundColor Green
        else {
            $message = "Target local folder exist at $localDownloadFolderPath"
            Write-Host $message -ForegroundColor Blue

        $localFilePath = Join-Path $localDownloadFolderPath $spolFileName

        $message = "Processing SharePoint file $spolFileName"
        Write-Host $message -ForegroundColor Green

        m365 spo file get --webUrl $spolSiteUrl --url $spolLibFileRelativeUrl --asFile --path $localFilePath

        $message = "Downloaded SharePoint file at $localFilePath"
        Write-Host $message -ForegroundColor Green

    $localFolderToSync = Join-Path $localFileDownloadFolderPath $localBaseFolderName
    az storage blob sync --account-key $azStorageAccountKey --account-name $azStorageAccountName -c $azStorageContainerName -s $localFolderToSync --only-show-errors | Out-Null

    $message = "Syncing local folder $localFolderToSync with Azure Storage Container $azStorageContainerName is completed"
    Write-Host $message -ForegroundColor Green
else {
    Write-Host "No files in $spolDocLibTitle library" -ForegroundColor Yellow

Bonus - Azure File Share

Azure Files offers fully managed cloud file shares that we can access from anywhere via the industry standard Server Message Block (SMB) protocol. Azure file shares are just like other file shares, but stored in the cloud and backed by the Azure platform.

This PowerShell script shows how to upload a file to Azure Storage File Share using Rest API.

$azStorageAccountKey = "*****************"
$azStorageAccountName = "azure-storage-account-name"
$azStorageFileShare = "azure-storage-fileshare-name"
$azStorageDirectoryPath = "azure-storage-fileshare-directory-path-or-name"
$localFileName = "filename.extension"

$scriptExePath = $PSScriptRoot

$localFilePath = $scriptExePath + "/" + $localFileName
$localFileLength = (Get-Item $localFilePath).length

$azStorageEndPointCreateFile = https://$($azStorageAccountName)$($azStorageFileShare)/$($azStorageDirectoryPath)/$($localFileName)?sv=$($azStorageAccountKey)

$requestHeadersCreateFile = @{
    "x-ms-type"           = "file"
    "x-ms-version"        = "2015-02-21"
    "x-ms-date"           = [System.DateTime]::UtcNow
    "x-ms-content-length" = $localFileLength

Invoke-RestMethod -Method Put -Uri $azStorageEndPointCreateFile -Headers $requestHeadersCreateFile

$azStorageEndPointFillFile = https://$($azStorageAccountName)$($azStorageFileShare)/$($azStorageDirectoryPath)/$($localFileName)?comp=range&sv=$($azStorageAccountKey)

$requestHeadersFillFile = @{
    "x-ms-version" = "2015-02-21"
    "x-ms-range"   = "bytes=0-$($localFileLength  1)"
    "x-ms-date"    = [System.DateTime]::UtcNow
    "x-ms-write"   = "update"

Invoke-RestMethod -Method Put -Uri $azStorageEndPointFillFile -Headers $requestHeadersFillFile -InFile $localFilePath

Thank you Mikael Sand for your support to fix the file upload issue.



I hope you find this post helpful.