What it does
Four CSV-driven operations against SharePoint Online, all from one workspace at app.migrationfox.com/governance/bulk-provisioning:
| Operation | What it writes | Scope |
|---|---|---|
| Navigation | Top-nav or QuickLaunch nodes with parent/child hierarchy | Per-site |
| Theme | Modern Fluent UI theme to tenant catalog + applies to selected sites | Tenant catalog + per-site apply |
| Content Types | Custom CTs inheriting from Document, Item, Folder, Site Page, etc. | One site — or the Content Type Hub for tenant-wide rollout |
| Term Store | Groups, term sets, and terms in the managed metadata service | Tenant-wide global store OR site-local term store |
Permissions
Each operation has its own permission floor. Bulk Provisioning calls real SharePoint admin endpoints, so the signed-in user needs the right SharePoint role — not just an OAuth scope.
- Navigation: Site Collection Administrator on the target site.
- Theme: SharePoint Administrator role in Entra ID for tenant catalog writes; the tool auto-elevates the signed-in user to Site Collection Admin via the tenant admin REST
SetSiteAdminbefore each per-siteApplyTheme, so site-level apply works for SP Admins automatically. - Content Types: Site Collection Admin on the target site (or on
/sites/contentTypeHubfor tenant-wide deploy). - Term Store: Term Store Administrator role in the SharePoint Admin Center (Admin Center → More features → Term store → Admins) AND
TermStore.ReadWrite.AllMicrosoft Graph delegated permission with admin consent on the connected app registration.
Global Administrator is not sufficient on its own — since Microsoft's 2024 RBAC tightening, the SharePoint Administrator role must be explicitly assigned for tenant theme catalog writes and Term Store admin operations.
Navigation builder
Builds a hierarchical nav from a flat CSV or JSON tree. Parent-child resolution happens via the tempId field — rows reference their parent by the parent row's tempId, not by the SharePoint-assigned node ID (which doesn't exist yet).
CSV columns
tempId,title,url,parentTempId
resources,Resources,,
res-supporting,Supporting People,,resources
forms,Forms and Tools,,
forms-hr,HR Forms,/sites/intranet/Forms/HR,forms
directory,Employee Directory,/sites/intranet/directory,
Fields
tempId— required. Stable string used to reference this node from children.title— required. The label shown in the nav bar.url— optional. Server-relative (/sites/x/y) or absolute (https://...). Cross-site URLs (anything starting/sites/or/teams/) are auto-markedIsExternalso SharePoint skips path validation.parentTempId— optional. Match a sibling row'stempIdto nest this node under it.
Theme deploy
Modern theme deploy via /_api/thememanager/UpdateTenantTheme (catalog) and /_api/thememanager/ApplyTheme (per site). The legacy composed-look /_api/web/applytheme endpoint is not used — it rejects modern theme names.
The palette accepts a 30-key Fluent UI JSON object (themePrimary, neutralLight, etc.). The tool tries AddTenantTheme first; if a theme with the same name already exists, it falls back to UpdateTenantTheme automatically — so re-runs during palette tuning don't error out.
Content Types
Creates content types via Microsoft Graph (POST /sites/{siteId}/contentTypes) which honors the supplied parentId reliably. The legacy SharePoint REST /contenttypes collection POST silently regenerated the supplied ID and forced everything under Item, which is why we route through Graph instead.
CSV columns
name,description,group,parentId,columnNames
MigrationFox-Document,"Branded document content type",MigrationFox,0x0101,
MigrationFox-Item,Default item content type for non-document records,MigrationFox,0x01,
MigrationFox-SitePage,"Branded modern page content type",MigrationFox,0x0101009D1CB255DA76424F860D91F20E6C4118,
Common parent IDs
0x01— Item0x0101— Document0x0120— Folder0x010109— Page0x0101009D1CB255DA76424F860D91F20E6C4118— Site Page (modern)0x010108— Wiki Page0x0107— Comment
Tenant-wide deploy via the Content Type Hub
Toggle Deploy to tenant Content Type Hub. The tool auto-fills the URL with https://<tenant>.sharepoint.com/sites/contentTypeHub derived from the selected credential. After creation, open each content type in SharePoint and choose Manage publishing → Publish to push it to every site in the tenant. Re-publish to roll out changes.
Term Store
The Term Store tab supports both Global (tenant-wide) and Site-level scopes. Tenant-wide writes use Microsoft Graph beta (/beta/termStore/groups) because /v1.0/termStore is not exposed at the tenant root. Site-level writes use the GA /v1.0/sites/{siteId}/termStore/groups endpoint. Term creation goes to /sets/{setId}/children — not /terms, which is the read-only flat-list view.
CSV columns
groupName,setName,termName,description
MigrationFox,Document Types,Contract,Signed legal agreements with customers and vendors
MigrationFox,Document Types,Statement of Work,Engagement-specific scope and deliverables
MigrationFox,Departments,Engineering,Product engineering and platform reliability
MigrationFox,Categories,Confidential,Sensitive customer and financial records
Existing groups and sets are looked up by name and reused (idempotent). Terms always create — for clean re-runs, delete the term set in SharePoint first.
Idempotent re-runs
Every operation is safe to re-run with the same CSV. Navigation looks up existing nodes by title before creating; Theme falls back from Add to Update; Content Types skip duplicate names; Term Store reuses existing groups and sets. The one exception is term creation, which always inserts — rerunning a CSV with the same term names will create duplicates inside the same set.
Sample downloads
Each section has Download sample and Upload file buttons. Download produces a working CSV/JSON with realistic enterprise content (the MigrationFox term group, three sample content types, etc.) you can adapt and re-upload. Files are read locally in the browser — nothing leaves the page until you click the action button.
Troubleshooting
"Cannot find resource for the request Add"
You're hitting an outdated tool version. The fix shipped 2026-05-06 — refresh the page; the modern endpoint is /_api/web/Navigation/{location} for navigation and /_api/web/contenttypes for content types, neither with a /Add suffix.
"Incompatible type kinds were found... 'Complex' instead of 'Entity'"
Same pattern as above. Bulk Provisioning auto-uses the right entity body shape (SP.NavigationNode with IsExternal) since 2026-05-06.
"Cannot open '/sites/X/Y': no such file or folder"
The navigation node references a path that doesn't exist on the target site. Cross-site URLs (anything under /sites/ or /teams/ different from the target) are auto-flagged as external so SharePoint stops path-validating them. If your URL is on the same site collection, double-check the case-sensitive path.
HTTP 403 on ApplyTheme
The signed-in user lacks Site Collection Admin on the target. The tool auto-elevates via SetSiteAdmin before each call, but that requires SharePoint Administrator in Entra. Assign the role at Entra ID → Roles and administrators → SharePoint Administrator and retry.
"Resource not found for the segment 'termStore'"
You're on Microsoft Graph v1.0. Bulk Provisioning routes the Global term store scope to /beta/termStore automatically since Microsoft never promoted it to v1.0. Site-local term store stays on v1.0.
"Resource not found for the segment 'terms'" or HTTP 400 on term creation
Old endpoint. Term creation goes to /sets/{setId}/children; /terms is the read-only flat-list view. Refresh the page and retry.
Term Store accessDenied: insufficient permissions
Two requirements:
- The connected Entra app must have TermStore.ReadWrite.All Microsoft Graph delegated permission with admin consent granted.
- The signed-in user must be a Term Store Administrator in the SharePoint Admin Center (Admin Center → More features → Term store → click root Taxonomy node → right pane shows Admins).
Both are required — one without the other still 403s.
Pricing
Bulk Provisioning is included in the Tenant Suite ($1,599 / 1 year / 1 tenant) and Consultant Pro ($2,499/yr / unlimited tenants for one consultant) tiers. It is not sold individually because the deploy pillar's value comes from re-running it many times during a rollout, not as a one-shot audit.