Update Folder Approval Status
This PnP PowerShell script automates the management of folder approval status in SharePoint Online document libraries. It helps maintain content governance by programmatically updating approval workflows and status across multiple folders.
Purpose
Folder approval management enables you to:
- Bulk update approval status across folders
- Maintain content governance standards
- Automate document workflow processes
- Ensure compliance with approval policies
Prerequisites
- PnP PowerShell module installed
- List/library edit permissions or higher
- Content approval enabled on target libraries
- Connection to your SharePoint Online site
PowerShell Script
# Error handling for the entire script
try {
# Connect to your SharePoint site
$ClientId = ""
Connect-PnPOnline -Url "https://tenantName.sharepoint.com/sites/siteName" -Interactive -ClientId $ClientId
Write-Host "Successfully connected to SharePoint." -ForegroundColor Green
}
catch {
Write-Host "Failed to connect to SharePoint: $($_.Exception.Message)" -ForegroundColor Red
# Create error result for CSV
$errorResult = [PSCustomObject]@{
DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
FolderPath = "N/A"
FolderName = "N/A"
Status = "Connection Error"
Message = "Failed to connect to SharePoint: $($_.Exception.Message)"
PreviousStatus = "N/A"
}
# Export error to CSV
$csvFileName = "SharePoint_Folder_Approval_Results_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$csvPath = Join-Path $PSScriptRoot $csvFileName
@($errorResult) | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Host "Error logged to: $csvPath" -ForegroundColor Yellow
exit 1
}
# Initialize array to store results for CSV output
$results = @()
Write-Host "Searching for folders with PENDING status (2) in Site Pages library..." -ForegroundColor Cyan
# Get ALL items from Site Pages library (including nested folders)
# _ModerationStatus: 0 = Approved, 1 = Rejected, 2 = Pending, 3 = Draft
try {
Write-Host "Getting ALL items from Site Pages library to find nested folders..." -ForegroundColor Cyan
# Get ALL items with a high page size to ensure we get everything including subfolders
$allItems = Get-PnPListItem -List "Site Pages" -PageSize 2000
Write-Host "Retrieved $($allItems.Count) total items from Site Pages library." -ForegroundColor Green
# Filter to only folders (including nested ones) - use FileSystemObjectType as primary method
$allFolders = $allItems | Where-Object { $_.FileSystemObjectType -eq "Folder" }
Write-Host "Found $($allFolders.Count) folders using FileSystemObjectType detection." -ForegroundColor Cyan
# Show all folders we found with their paths
Write-Host "`nAll folders found:" -ForegroundColor Yellow
foreach ($folder in $allFolders) {
$folderName = $folder["FileLeafRef"]
$folderPath = $folder["FileRef"]
$moderationStatus = $folder["_ModerationStatus"]
Write-Host " - '$folderName'" -ForegroundColor White
Write-Host " Path: '$folderPath' | Status: $moderationStatus" -ForegroundColor Gray
}
# Filter for folders with PENDING status (2) using PowerShell
$foldersToApprove = $allFolders | Where-Object { $_["_ModerationStatus"] -eq 2 }
Write-Host "`nFound $($foldersToApprove.Count) folders with PENDING status that need approval." -ForegroundColor Green
# Show what we found that needs approval
if ($foldersToApprove.Count -gt 0) {
Write-Host "`nFolders with PENDING status (will be approved):" -ForegroundColor Red
foreach ($folder in $foldersToApprove) {
$folderName = $folder["FileLeafRef"]
$folderPath = $folder["FileRef"]
$moderationStatus = $folder["_ModerationStatus"]
Write-Host " - '$folderName' | Path: '$folderPath' | Status: $moderationStatus" -ForegroundColor White
}
}
}
catch {
Write-Host "Failed to query Site Pages library: $($_.Exception.Message)" -ForegroundColor Red
# Create error result for CSV
$result = [PSCustomObject]@{
DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
FolderPath = "N/A"
FolderName = "N/A"
Status = "Query Error"
Message = "Failed to query Site Pages library: $($_.Exception.Message)"
PreviousStatus = "N/A"
}
$results += $result
# Export error and exit
$csvFileName = "SharePoint_Folder_Approval_Results_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$csvPath = Join-Path $PSScriptRoot $csvFileName
$results | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Host "Error logged to: $csvPath" -ForegroundColor Yellow
exit 1
}
if ($foldersToApprove.Count -eq 0) {
Write-Host "No folders found that require approval." -ForegroundColor Green
# Still create a CSV to document the run
$result = [PSCustomObject]@{
DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
FolderPath = "N/A"
FolderName = "N/A"
Status = "No Action Required"
Message = "All folders already approved"
PreviousStatus = "N/A"
}
$results += $result
}
else {
Write-Host "`nProcessing $($foldersToApprove.Count) folder(s) that need approval..." -ForegroundColor Yellow
# Loop through each folder and approve it
foreach ($folder in $foldersToApprove) {
# Initialize variables to avoid scope issues
$folderName = "Unknown"
$folderPath = "Unknown"
$currentStatus = "Unknown"
# Create result object for this folder
$result = [PSCustomObject]@{
DateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
FolderPath = ""
FolderName = ""
Status = ""
Message = ""
PreviousStatus = ""
}
try {
# Safely extract folder properties with null checks
$folderName = if ($folder["FileLeafRef"]) { $folder["FileLeafRef"] } else { "Unknown" }
$folderPath = if ($folder["FileRef"]) { $folder["FileRef"] } else { "Unknown" }
$currentStatus = if ($null -ne $folder["_ModerationStatus"]) { $folder["_ModerationStatus"] } else { "Unknown" }
# Update result object with extracted values
$result.FolderPath = $folderPath
$result.FolderName = $folderName
$result.PreviousStatus = $currentStatus
Write-Host "Processing folder: '$folderName' (Current status: $currentStatus)"
# Approve the folder
$folder["_ModerationStatus"] = 0 # 0 = Approved
$folder.Update()
Invoke-PnPQuery
Write-Host "✓ Folder '$folderName' approved successfully" -ForegroundColor Green
$result.Status = "Success"
$result.Message = "Folder approved successfully (was status: $currentStatus)"
}
catch {
$errorMessage = $_.Exception.Message
Write-Host "✗ Failed to approve folder '$folderName': $errorMessage" -ForegroundColor Red
$result.FolderPath = $folderPath
$result.FolderName = $folderName
$result.PreviousStatus = $currentStatus
$result.Status = "Error"
$result.Message = "Failed to approve: $errorMessage"
}
# Add result to array
$results += $result
}
}
# Generate CSV output file
$csvFileName = "SharePoint_Folder_Approval_Results_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$csvPath = Join-Path $PSScriptRoot $csvFileName
try {
$results | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Host "`nCSV results exported to: $csvPath" -ForegroundColor Cyan
}
catch {
Write-Host "`nFailed to export CSV: $($_.Exception.Message)" -ForegroundColor Red
}
Write-Host "`nFolder approval process completed."
Usage Notes
- Verify content approval is enabled on target libraries
- Test script with a small subset before bulk operations
- Consider notification requirements for status changes
- Ensure appropriate permissions for approval actions