Dragging files into a SharePoint library in the browser is fine for a handful of documents. When you need to move a few hundred reports from a file share, rebuild a folder tree, or set columns like Department on every file, a script is faster and you can run it again next month.
Here’s how I upload files to a SharePoint Online document library with PnP PowerShell: one file, a file with metadata, every file in a folder, and a whole folder with its subfolders. I ran every script in PowerShell 7 with PnP PowerShell 3.3.0 against my own Microsoft 365 tenant, and the screenshots show the real output.
Quick answer: Connect with Connect-PnPOnline, then run Add-PnPFile -Path "C:\Reports\Report.pdf" -Folder "Shared Documents". Use the library’s URL name in -Folder (Shared Documents, not Documents) and add a subfolder path like Shared Documents/Sales/2026 to upload into a folder; missing folders are created for you. Add -Values @{Department="Sales"} to set columns.
Before you start: connect and find the library’s URL name
You need the PnP.PowerShell module, an Entra ID app registration for sign-in, and at least Edit (Contribute) permission on the library. If the module isn’t set up yet, follow installing PnP PowerShell for SharePoint Online first, because current versions require your own app’s client ID.
Install-Module PnP.PowerShell -Scope CurrentUser # once, PowerShell 7.4 or later
$siteUrl = "https://contoso.sharepoint.com/sites/Finance"
$clientId = "<your Entra ID app (client) ID>"
Connect-PnPOnline -Url $siteUrl -ClientId $clientId -Interactive
# Find the library's URL name (use this in -Folder)
(Get-PnPList -Identity "Contoso Demo Uploads").RootFolder.ServerRelativeUrl
The last line matters more than it looks. -Folder expects the library’s URL name, which often differs from the title you see in the browser. The default library is titled Documents but lives at Shared Documents. A library created as “Contoso Demo Uploads” through PnP with -Url ContosoDemoUploads lives at ContosoDemoUploads.
Upload a single file with Add-PnPFile
Add-PnPFile takes the local file in -Path and the destination in -Folder. The folder path is site-relative: the library’s URL name, optionally followed by subfolders. Use -NewFileName when the file should get a different name in SharePoint.
Add-PnPFile -Path "C:\Reports\Q3-2026-Sales-Summary.pdf" -Folder "Shared Documents"
# Upload under a different name
Add-PnPFile -Path "C:\Reports\Meeting-Notes.txt" -Folder "Shared Documents" `
-NewFileName "Ops-Meeting-Notes-10-05-2026.txt"

Look at the last line of the output. Uploading a file with the same name didn’t fail or create a copy: Add-PnPFile replaced it, and because versioning is on, SharePoint saved the old one as version 1.0. There’s no -Overwrite switch in PnP PowerShell, even though some older guides show one. Replacing is the default behavior.
Here are the parameters you’ll use most often:
| Parameter | What it does |
|---|---|
-Path | Local file to upload |
-Folder | Site-relative destination folder (required) |
-NewFileName | Name to use in SharePoint |
-Values | Hashtable of column values, keyed by internal name |
-ContentType | Content type to assign to the file |
-Checkout, -CheckInComment | Check out the existing file first, then check in with a comment |
-Publish, -Approve | Publish a major version or approve it when the library requires it |
-Stream / -Content with -FileName | Upload from a stream or create a file from text |
Upload into a folder or subfolder
Add the folder path after the library name. If any folder in the path doesn’t exist, Add-PnPFile creates it before uploading, so you don’t need a separate step.
If you want the folders in place first, Resolve-PnPFolder returns a folder and creates it, with any missing parents, when it isn’t there. To plan a structure from scratch, see creating a document library with folders using PnP PowerShell.