A free and open source Windows desktop application for copying files, libraries, and pages between SharePoint Online site collections — preserving version history, metadata, and custom columns.
- Download the latest
.exefrom the Releases page — it is a self-contained single-file binary, no extraction needed. - Register an Azure AD app — follow the Azure AD App Registration steps below to create an app registration in your tenant.
- Launch
SharePointSmartCopy.exe, open Settings (⚙ top-right), and enter your Client ID and Tenant ID. - Connect and copy — enter your source site URL, sign in with your Microsoft 365 account, choose a scope, and follow the wizard.
Windows SmartScreen may show a warning on first launch because the binary is downloaded from the internet. Click More info → Run anyway. No .NET runtime installation is required — the runtime is bundled in the executable.
Choose from four copy scopes in a step-by-step wizard:
| Scope | What it copies |
|---|---|
| Files | Selected files and folders from a document library, with full version history and metadata |
| Libraries & Lists | Entire document libraries or generic lists — schema, columns, versioning settings, and content |
| Site | All document libraries and custom lists on a source site, plus optional navigation links |
| Pages | Modern SharePoint pages (.aspx), with optional web part URL remapping |
All scopes:
- Custom column values copied — including Person/User and Managed Metadata columns
- Custom column mapping dialog — map source columns to target columns, or create missing columns in the target
- Overwrite / skip / copy-if-newer incremental mode
- HTTP 429 throttle handling — automatic Retry-After backoff so large jobs complete without manual intervention
- Detailed per-item report with CSV export and inline permission status
- Run history viewable in-app
Files scope:
- Full version history — version numbers, dates, and per-version editors preserved exactly
- Bulk copy with 1–16 parallel operations
- Migration API mode for high-fidelity large batches; Enhanced REST for small or quick copies
Appearance:
- Light / Dark / System theme — switchable in Settings
| Requirement | Detail |
|---|---|
| OS | Windows 10 or 11 |
| .NET Runtime | .NET 8 Desktop Runtime (x64) |
| Microsoft 365 | SharePoint Online tenant |
| Azure AD | App registration with delegated API permissions (see below) |
- Go to Entra ID → App registrations → New registration
- Name:
SharePoint Smart Copy(or similar) - Supported account types: Single tenant (your org only) or Multitenant as needed
- Redirect URI: Public client/native →
http://localhost - Click Register
- Copy the Application (client) ID and Directory (tenant) ID — you will enter these in the app's Settings dialog
Go to API permissions → Add a permission:
| API | Type | Permission | Purpose |
|---|---|---|---|
| Microsoft Graph | Delegated | Sites.ReadWrite.All |
Browse and read SharePoint sites/files via Graph |
| Microsoft Graph | Delegated | Files.ReadWrite.All |
Upload/download file content via Graph |
| SharePoint | Delegated | AllSites.FullControl |
Required by the Migration API to submit migration jobs; also allows correct IsSiteAdmin evaluation in the OAuth context |
Why
AllSites.FullControl? SharePoint's Migration API (CreateMigrationJobEncrypted) performs a server-side site-collection-administrator check. With onlySites.ReadWrite.All, SharePoint caps the effective OAuth privilege below site-collection-admin level — meaning even a user who is explicitly a Primary Site Admin will be rejected.AllSites.FullControlraises the OAuth context to full control so SP recognizes the user's actual admin status.
AllSites.FullControlis only required for Migration API mode. If your organization uses Enhanced REST mode exclusively, this permission can be omitted.
After adding the permissions, click Grant admin consent for [your organization] at the top of the API permissions list. This pre-authorizes the permissions org-wide so users are never prompted for individual consent.
Without admin consent, users will see an interactive consent dialog on first use. As a Global Admin you can also check "Consent on behalf of your organization" in that dialog, which has the same effect.
The account running the copy must be a Site Collection Administrator on the target site:
Site Settings → Site Collection Administrators → add your account
Being a Global Admin or SharePoint Admin grants effective access to all sites but does not automatically populate the Site Collection Administrators list for a specific site. You must add the account explicitly.
This requirement applies only to Migration API mode. Enhanced REST mode works with standard contributor access.
Launch the app and open Settings (gear icon):
- Client ID — Application (client) ID from the app registration
- Tenant ID — Directory (tenant) ID (leave blank for multi-tenant)
Source/target URLs and copy preferences are configured within the wizard and remembered between sessions.
When copying files with version history enabled, two copy modes are available.
| Scenario | Recommended mode |
|---|---|
| Large batch (50+ files or 200+ versions) | Migration API |
| Full version history fidelity required | Migration API |
| Small batch or a quick one-off copy | Enhanced REST |
| Copying current version only (no history) | Enhanced REST |
| User lacks Site Collection Admin rights | Enhanced REST |
| Need to see per-file progress in real time | Enhanced REST |
The copy mode option appears in Advanced options on the Options screen when Copy versions is enabled.
Uses SharePoint's built-in Migration API. Files are packaged client-side, uploaded to SP-provisioned Azure Blob containers, then imported server-side by SharePoint.
Advantages
- Version numbers on target exactly match source (1.0, 2.0, 3.0, …)
- Modified By and Modified date correct per version in history
- Author and Created date preserved on the file
- Bypasses per-item throttling — SP processes the batch as a single job, not thousands of individual API calls
- Scales well: 500 files with 10 versions each has roughly the same client-side overhead as 50 files
Limitations
- Minimum ~1–2 minutes of overhead per run regardless of file count (container provisioning, manifest packaging, blob upload, SP processing)
- No per-file progress during SP's processing phase — results appear only after the full job completes
- Error reporting is at the job level; individual file failures may have limited detail
- Requires elevated permissions (see above)
Uses the SharePoint REST and Microsoft Graph APIs directly. Each file version is uploaded individually, with metadata and timestamps patched immediately after.
Advantages
- Results appear per file as each one completes — you see progress in real time
- Low overhead for small batches: a 5-file copy completes in seconds
- No elevated permissions required beyond standard contributor access
- Per-file error messages are clear and immediate
Limitations
- Version numbers are 2× the source count (e.g. versions 2, 4, 6 for a 3-version source file) — a SharePoint REST constraint; the correct dates and editors are still preserved
- Subject to SharePoint throttling (HTTP 429) on large batches with high parallelism
- Slower than Migration API for large migrations with many versions
"Migration job rejected — access denied" even though I'm a Site Admin
The Migration API requires the OAuth token to carry AllSites.FullControl. Without it, SharePoint rejects the request regardless of the user's actual admin role. Add AllSites.FullControl to the app registration's API permissions and re-grant admin consent.
"Migration API failed" but I have AllSites.FullControl The running account must also appear explicitly in Site Settings → Site Collection Administrators on the target site. Being a Global Admin or SharePoint Admin at the tenant level is not sufficient — you must add the account to that specific site's administrators list.
Consent dialog appears on every sign-in Admin consent has not been granted for the app registration. A Global Admin must click Grant admin consent for [organization] on the API permissions page in Entra ID, or check "Consent on behalf of your organization" the first time the consent dialog appears.
Sign-in browser window does not open The app has no Client ID configured. Open Settings (⚙ top-right) and enter the Application (client) ID from your Azure AD app registration.
"File is checked out at source" errors in the report Files checked out in SharePoint cannot be read by the API. Check them in at the source before copying, or use the CSV export from the report to identify and retry them individually.
| Package | Version | Purpose |
|---|---|---|
Microsoft.Graph |
5.x | Graph API client (site/file browsing, download, Enhanced REST upload) |
Microsoft.Identity.Client |
4.x | MSAL — interactive sign-in and token management |
Azure.Storage.Blobs |
12.x | Upload encrypted blobs to SP-provisioned containers (Migration API) |
Microsoft.SharePointOnline.CSOM |
16.x | EncryptionOption type used in Migration API package |
CommunityToolkit.Mvvm |
8.x | MVVM source generators for the WPF view models |
MIT © 2026 Sean Regan





