Skip to content

Commit 0897d15

Browse files
authored
Merge pull request #864 from jeppesc11/spo-list-contenttype-migration
🔨 - Added SharePoint List Content Type Migration with Data Preservati…
2 parents 8c762ed + aa4fd80 commit 0897d15

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# SharePoint List Content Type Migration with Data Preservation
2+
3+
This sample shows how to update a SharePoint list to use a different content type using PowerShell PnP.
4+
5+
⚠️ **Disclaimer**: This will only work if the columns in the Content Type match those already present in the list.
6+
7+
## Summary
8+
9+
This PowerShell script demonstrates how to update a SharePoint list to use a specific content type. The script connects to a SharePoint site, retrieves the target list, and updates its content types configuration.
10+
11+
## How It Works 🤔
12+
13+
The script follows this process:
14+
15+
1. **Create a Content Type**: First, create your content type in SharePoint
16+
2. **Export as Template**: Use `Get-PnPSiteTemplate` to export the content type as a PnP template XML file
17+
3. **Run the Script**: The script will:
18+
- Load all list items with their values into memory 🧠
19+
- Remove the old columns that need to be replaced 🗑️
20+
- Apply the PnP template containing the new content type
21+
- Restore all values into the new columns ✅
22+
23+
## Complete Column Migration
24+
25+
When you need to replace existing columns with new ones from a content type:
26+
27+
```powershell
28+
# Required variables for advanced mode
29+
$siteUrl = "https://xxx.sharepoint.com/sites/xxx"
30+
$listName = "YourListName"
31+
$contentTypeName = "YourContentTypeName"
32+
$columnsToMap = @("Column1", "Column2", "Column3") # Replace with actual column names
33+
$userFields = @("AssignedTo", "CreatedBy") # Replace with actual user field names if needed
34+
$templatePath = "..\ContentTypeTemplate.xml"
35+
36+
# Connect to SharePoint Online
37+
Connect-PnPOnline -Url $siteUrl -Interactive
38+
39+
# Enable content type management on the list
40+
Set-PnPList -Identity $listName -EnableContentTypes $true
41+
Write-Host "Content types enabled on the list."
42+
43+
# Backup data from old columns
44+
$items = Get-PnPListItem -List $listName -PageSize 5000
45+
$backupData = @{}
46+
47+
foreach ($item in $items) {
48+
$itemData = @{}
49+
# Backup old column data
50+
foreach ($column in $columnsToMap) {
51+
$itemData[$column] = $item[$column]
52+
}
53+
$backupData[$item.Id] = $itemData
54+
}
55+
56+
# Remove old columns
57+
foreach ($column in $columnsToMap) {
58+
Remove-PnPField -List $listName -Identity $column -Force
59+
Write-Host "Removed old column:" $column
60+
}
61+
62+
# Apply PnP Provisioning Template
63+
Invoke-PnPSiteTemplate -Path $templatePath
64+
Write-Host "PnP template applied to the site."
65+
66+
# Get the content type
67+
$contentType = Get-PnPContentType -Identity $contentTypeName
68+
69+
# Add the content type to the list
70+
Add-PnPContentTypeToList -List $listName -ContentType $contentType
71+
Write-Host "Content type added to the list."
72+
73+
# Update items to the new content type and restore data to new columns
74+
foreach ($item in $items) {
75+
$itemId = $item.Id
76+
$itemData = $backupData[$itemId]
77+
78+
# Handle user fields
79+
foreach ($userField in $userFields) {
80+
if ($itemData[$userField]) {
81+
$UserDto = $itemData[$userField];
82+
write-host "User: " $UserDto.Email
83+
84+
$itemData[$userField] = $UserDto.Email
85+
}
86+
}
87+
88+
# Update item content type
89+
Set-PnPListItem -List $listName -Identity $itemId -Values @{"ContentTypeId" = $contentType.Id }
90+
91+
# Restore data to new columns
92+
Set-PnPListItem -List $listName -Identity $itemId -Values $itemData
93+
Write-Host "Updated item ID:" $itemId
94+
}
95+
96+
Write-Host "All items updated to the new content type and old columns removed."
97+
98+
# Disconnect from SharePoint Online
99+
Disconnect-PnPOnline
100+
```
101+
102+
### What the Script Does 🛠️
103+
104+
1. **Enable Content Types**: Enables content type management on the list
105+
2. **Backup Data**: Loads all rows with their values into memory 🧠
106+
3. **Remove Old Columns**: Removes the columns specified in `$columnsToMap` 🗑️
107+
4. **Apply Template**: Invokes the PnP template containing the new content type
108+
5. **Add Content Type**: Adds the new content type to the list
109+
6. **Restore Data**: Reloads all values into the new columns ✅
110+
7. **Handle User Fields**: Properly processes user/people picker fields
111+
112+
### Limitations ⚠️
113+
114+
As mentioned, this script doesn't solve everything:
115+
- Any views created with the old columns will no longer work, even if the new columns have the same name
116+
- Custom forms may need to be updated
117+
- Workflows referencing old columns may break
118+
- There's definitely room for improvement in the script
119+
120+
## Contributors
121+
122+
| Author(s) |
123+
| ------------------------------- |
124+
| [Jeppe Spanggaard](https://github.com/jeppesc11) |
125+
126+
127+
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
128+
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-list-contenttype-migration" aria-hidden="true" />
58.7 KB
Loading
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
[
2+
{
3+
"name": "spo-list-contenttype-migration",
4+
"source": "pnp",
5+
"title": "SharePoint List Content Type Migration with Data Preservation",
6+
"shortDescription": "Migrate SharePoint list to new content type while preserving all existing data",
7+
"url": "https://pnp.github.io/script-samples/spo-list-contenttype-migration/README.html",
8+
"longDescription": [
9+
"This PowerShell script demonstrates how to migrate a SharePoint list to use a different content type while preserving all existing data. The script backs up existing column data, removes old columns, applies a PnP provisioning template with the new content type, and restores all data to the new columns. Perfect for scenarios where you need to replace existing columns with new ones from a content type without losing any data."
10+
],
11+
"creationDateTime": "2025-07-29",
12+
"updateDateTime": "2025-07-29",
13+
"products": [
14+
"SharePoint"
15+
],
16+
"metadata": [
17+
{
18+
"key": "PNP-POWERSHELL",
19+
"value": "3.1.0"
20+
}
21+
],
22+
"categories": [
23+
"Modernize",
24+
"Data",
25+
"Migration"
26+
],
27+
"tags": [
28+
"Connect-PnPOnline",
29+
"Set-PnPList",
30+
"Get-PnPListItem",
31+
"Remove-PnPField",
32+
"Invoke-PnPSiteTemplate",
33+
"Get-PnPContentType",
34+
"Add-PnPContentTypeToList",
35+
"Set-PnPListItem",
36+
"Disconnect-PnPOnline"
37+
],
38+
"thumbnails": [
39+
{
40+
"type": "image",
41+
"order": 100,
42+
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/spo-list-contenttype-migration/assets/preview.png",
43+
"alt": "Preview of SharePoint List Content Type Migration with Data Preservation"
44+
}
45+
],
46+
"authors": [
47+
{
48+
"gitHubAccount": "jeppesc11",
49+
"company": "",
50+
"pictureUrl": "https://github.com/jeppesc11.png",
51+
"name": "Jeppe Spanggaard"
52+
}
53+
],
54+
"references": [
55+
{
56+
"name": "Want to learn more about PnP PowerShell and the cmdlets",
57+
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
58+
"url": "https://aka.ms/pnp/powershell"
59+
}
60+
]
61+
}
62+
]

0 commit comments

Comments
 (0)