Create Folder Structure
This PnP PowerShell script automates the creation of standardized folder structures in SharePoint Online document libraries. Build consistent organizational hierarchies to improve content management and user navigation.
Purpose
This script helps you:
- Create standardized folder hierarchies across document libraries
- Ensure consistent organizational structure for content management
- Automate folder creation for project templates and workflows
- Implement governance policies through structured folder organization
Prerequisites
- PnP PowerShell module installed
- Site collection administrator permissions
- Connection to your SharePoint Online site
- Access to target document libraries
- Appropriate folder creation permissions
PowerShell Script
<#
.SYNOPSIS
Creates a folder structure in a SharePoint Online library from a JSON configuration file.
Uses Resolve-PnPFolder which creates the folder if it doesn't exist, skips if it does.
#>
# ── Configuration — update these before running ───────────────
$SiteUrl = "https://tenantName.sharepoint.com/sites/siteName"
$ClientId = ""
$ConfigPath = ""
# ─────────────────────────────────────────────────────────────
# ── Load and validate configuration ──────────────────────────
if (-not (Test-Path $ConfigPath)) {
Write-Error "Configuration file not found at: $ConfigPath"
exit 1
}
try {
$config = Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json
}
catch {
Write-Error "Failed to parse JSON configuration: $($_.Exception.Message)"
exit 1
}
$targetLibrary = $config.folderStructure.targetLibrary
$folderHierarchy = $config.folderStructure.folderHierarchy
if (-not $targetLibrary) {
Write-Error "targetLibrary is missing from the configuration file."
exit 1
}
# ── Connect ───────────────────────────────────────────────────
Write-Host "Connecting to SharePoint..." -ForegroundColor Cyan
Connect-PnPOnline -Url $SiteUrl -Interactive -ClientId $ClientId
Write-Host "Connected successfully" -ForegroundColor Green
# ── Verify target library exists ─────────────────────────────
$library = Get-PnPList -Identity $targetLibrary -ErrorAction SilentlyContinue
if (-not $library) {
Write-Error "Library '$targetLibrary' was not found on this site."
Disconnect-PnPOnline
exit 1
}
Write-Host "Target library: $targetLibrary" -ForegroundColor Cyan
# ── Recursive folder creation using Resolve-PnPFolder ────────
function New-FolderRecursive {
param(
[string]$LibraryName,
[string]$ParentSiteRelativePath,
[PSCustomObject]$FolderNode
)
$folderName = $FolderNode.name
if (-not $folderName) { return }
# Resolve-PnPFolder takes a site-relative path
$siteRelativePath = "$ParentSiteRelativePath/$folderName"
try {
Resolve-PnPFolder -SiteRelativePath $siteRelativePath -ErrorAction Stop | Out-Null
Write-Host " Resolved: $siteRelativePath" -ForegroundColor Green
}
catch {
Write-Host " Failed: $siteRelativePath — $($_.Exception.Message)" -ForegroundColor Red
return
}
# Recurse into sub-folders
if ($FolderNode.subFolders) {
foreach ($subFolder in $FolderNode.subFolders) {
New-FolderRecursive `
-LibraryName $LibraryName `
-ParentSiteRelativePath $siteRelativePath `
-FolderNode $subFolder
}
}
}
# ── Process top-level folders ─────────────────────────────────
Write-Host "`nProvisioning folder structure...`n" -ForegroundColor Cyan
foreach ($topFolder in $folderHierarchy) {
New-FolderRecursive `
-LibraryName $targetLibrary `
-ParentSiteRelativePath $targetLibrary `
-FolderNode $topFolder
}
# ── Summary ────────────────────────────────────────────────────
Write-Host "`n── Run complete ────────────────────────────────" -ForegroundColor Cyan
Write-Host "Library : $targetLibrary"
Write-Host "Top-level folders: $($folderHierarchy.Count)"
Write-Host "View the library : $SiteUrl/$targetLibrary"
Disconnect-PnPOnline
Write-Host "Disconnected." -ForegroundColor Cyan
JSON Configuration File
{
"folderStructure": {
"targetLibrary": "SitePages",
"createPermissions": "Inherit",
"folderHierarchy": [
{
"name": "Projects",
"description": "Project documentation and deliverables",
"subFolders": [
{
"name": "2024 Projects",
"subFolders": [
{"name": "Project Alpha"},
{"name": "Project Beta"},
{"name": "Project Gamma"}
]
},
{
"name": "2025 Projects",
"subFolders": [
{"name": "Planning"},
{"name": "Active"},
{"name": "Completed"}
]
}
]
},
{
"name": "DocTemplates",
"description": "Document templates and standards",
"subFolders": [
{"name": "Proposals"},
{"name": "Reports"},
{"name": "Presentations"}
]
},
{
"name": "Archive",
"description": "Historical documents and records",
"subFolders": [
{"name": "2023"},
{"name": "2022"},
{"name": "2021"}
]
},
{
"name": "Policies",
"description": "Organizational policies and procedures",
"subFolders": [
{"name": "HR Policies"},
{"name": "IT Policies"},
{"name": "Financial Policies"}
]
}
]
},
"folderSettings": {
"setUniquePermissions": false,
"inheritFromParent": true,
"defaultContentType": "Document",
"enableVersioning": true
}
}
Usage Notes
- Plan folder hierarchy carefully before implementation
- Consider folder depth limitations and navigation usability
- Test folder creation on a small subset before bulk operations
- Document folder naming conventions and organizational standards
- Consider folder-level permissions and security requirements
- Avoid excessive nesting that may impact user experience
Best Practices
- Keep folder names short and descriptive
- Use consistent naming conventions across sites
- Limit folder depth to 3-4 levels for usability
- Consider metadata columns as alternatives to deep folder structures
- Document folder purposes and usage guidelines