PowerShell Script to Bulk Upload Files to SharePoint Online

PowerShell Script to Bulk Upload Files to SharePoint Online

Migrating on-premises file shares to Microsoft 365 or regularly uploading batches of reports to a SharePoint Document Library can be incredibly tedious if done manually through the browser. For enterprise-scale file transfers, the browser interface is inefficient and prone to timeouts.

Using PnP PowerShell, administrators can automate bulk file uploads, ensuring reliability, maintaining folder structures, and logging every successful (or failed) transfer.

In this guide, we will walk through a robust PowerShell script designed to bulk upload local files to SharePoint Online securely.

1. Setting Up Secure Authentication

Before running any scripts, ensure you have the PnP PowerShell module installed. When interacting with SharePoint Online, always use modern authentication.

For administrator-driven execution, interactive login is recommended. For scheduled migration jobs, utilize certificate-based authentication.


# Install the module if necessary
# Install-Module -Name PnP.PowerShell -Scope CurrentUser

# Optional: Configure default ClientId once if your tenant requires a specific App Registration
[System.Environment]::SetEnvironmentVariable('ENTRAID_CLIENT_ID', 'Your-client-id', 'User')

$SiteUrl = "https://contoso.sharepoint.com/sites/Migrations"

# Connect interactively
Connect-PnPOnline `
    -Url $SiteUrl `
    -Interactive

Note: For Interactive authentication, the authenticated user must have sufficient permissions on the target SharePoint site. If you are using an Entra ID App Registration, ensure the delegated permissions required by your scenario (like Sites.ReadWrite.All) have been granted and consented.

2. The Core Bulk Upload Script with Retry and CSV Logging

The Add-PnPFile cmdlet is the engine for uploading files. To bulk upload an entire directory, we need to retrieve all local files, determine their relative paths, ensure the destination folder exists, and then upload the file.

In production environments, SharePoint Online may throttle requests or encounter transient network errors. A robust script must include a retry mechanism and detailed CSV logging for auditing.


$LocalDirectory = "C:\Data\MigrationTarget"
$TargetLibrary = "Shared Documents"
$CsvLogPath = "C:\Logs\SP_Upload_Log.csv"

$Files = Get-ChildItem -Path $LocalDirectory -File -Recurse
$Results = @()

foreach ($File in $Files) {
    $MaxRetries = 3
    $RetryCount = 0
    $Success = $false

    # Calculate the relative folder path to maintain hierarchy
    $RelativePath = $File.DirectoryName.Replace($LocalDirectory, "").Replace("\", "/")
    $TargetFolder = "$TargetLibrary$RelativePath"
    
    # Resolve-PnPFolder creates missing folders automatically, ideal for preserving hierarchies
    Resolve-PnPFolder -SiteRelativePath $TargetFolder | Out-Null
    
    while (-not $Success -and $RetryCount -lt $MaxRetries) {
        try {
            Write-Host "Uploading $($File.Name) to $TargetFolder... (Attempt $($RetryCount + 1))" -ForegroundColor Cyan

            Add-PnPFile `
                -Path $File.FullName `
                -Folder $TargetFolder `
                -ErrorAction Stop | Out-Null
                
            Write-Host "Success: $($File.Name)" -ForegroundColor Green
            $Success = $true
            
            $Results += [PSCustomObject]@{
                FileName = $File.FullName
                Destination = $TargetFolder
                Status = "Success"
                Time = Get-Date
                ErrorMessage = ""
            }
        }
        catch {
            $RetryCount++
            Write-Warning "Failed to upload $($File.Name): $($_.Exception.Message)"
            
            if ($RetryCount -eq $MaxRetries) {
                $Results += [PSCustomObject]@{
                    FileName = $File.FullName
                    Destination = $TargetFolder
                    Status = "Failed"
                    Time = Get-Date
                    ErrorMessage = $_.Exception.Message
                }
            } else {
                # Wait before retrying (exponential backoff approach can be used here)
                Start-Sleep -Seconds 5
            }
        }
    }
}

# Export detailed results to CSV
$Results | Export-Csv -Path $CsvLogPath -NoTypeInformation
Write-Host "Migration complete. Log saved to $CsvLogPath" -ForegroundColor Yellow

3. Preserving Metadata (Dates and Authors)

When moving files, you might want to preserve the original Created or Modified dates, or map specific Authors and Editors.

You can achieve this by passing a dictionary of metadata to the -Values parameter in Add-PnPFile:


# Assuming $AuthorId and $EditorId are resolved SharePoint User IDs
Add-PnPFile `
    -Path $File.FullName `
    -Folder $TargetFolder `
    -Values @{
        "Created"  = $File.CreationTime;
        "Modified" = $File.LastWriteTime;
        "Author"   = $AuthorId;
        "Editor"   = $EditorId
    } `
    -ErrorAction Stop | Out-Null

4. Considerations for Enterprise Migrations and Large Files

For very large files or high-volume migrations, test upload performance carefully. While SharePoint Online supports files up to 250 GB, upload duration depends on network throughput, regional latency, and throttling conditions.

When migrating large departmental file shares or legacy file servers involving terabytes of content, evaluate the Microsoft SharePoint Migration Tool (SPMT) or Migration Manager. These tools provide built-in retry handling, reporting, incremental migrations, and large-scale migration optimization out of the box, making them superior to custom upload scripts for massive workloads.

Proactive Tip: Keeping Metadata Clean with SPClean

If your migration involves mapping legacy file owners to SharePoint columns (preserving the “Author” or “Editor” fields), you are directly referencing user accounts in your Entra ID environment.

Over time, as employees leave your organization, those accounts are disabled. These users become “Orphaned Users” in your SharePoint environment. While preserving historical metadata is important, orphaned users can clutter your site permissions and cause issues with compliance reporting and search indexing.

To manage this lifecycle securely, we recommend integrating SPClean into your maintenance routine. SPClean acts as an essential administrative assistant, proactively scanning your SharePoint sites to identify and safely remove or reassign orphaned users, keeping your directories clean and your M365 environment healthy.

Conclusion

PnP PowerShell is an excellent choice for recurring uploads, automation workflows, and small-to-medium migration projects. For large-scale enterprise migrations involving hundreds of gigabytes or millions of files, consider Microsoft Migration Manager or SharePoint Migration Tool alongside PowerShell automation for the best results.

© 2026 M365 Automation. All rights reserved. Designed for M365 Admins.