Logo
  • Contact form
  • Events & slides
  • Buy me a snack
👋🏻
/
📝
All Blogs
/Automate coping sites or lists in SharePoint Online
Automate coping sites or lists in SharePoint Online
Automate coping sites or lists in SharePoint Online

Automate coping sites or lists in SharePoint Online

Table of contents

  • When to use what
  • PNP - PowerShell
  • Create a site template
  • Pasting a site template
  • Copy with REST API
  • Copy a list
  • Pasting a list
☝
TL;DR - Copying single list or complete site collection can done using either PNP PowerShell or with the SharePoint Online REST API. Both have their advantages and disadvantages. I use the API method more with Power Power Platform solutions.

When to use what

👉

General disclaimer: Both tools are meant for the initial deployment of a site collection or its elements. Both cannot handle updates, at least I haven’t tried so far.

PNP - PowerShell
REST API
Description
A module you can install to your PowerShell locally. https://pnp.github.io/powershell/
API endpoints that are already available and can be executed using Power Automate. https://learn.microsoft.com/en-us/sharepoint/dev/declarative-customization/site-design-rest-api
Supported objects
ApplicationLifecycleManagement, AuditSettings, ComposedLook, ContentTypes, CustomActions, ExtensibilityProviders, Features, Fields, Files, ImageRenditions, Lists, Navigation, PageContents, Pages, PropertyBagEntries, Publishing, RegionalSettings, SearchSettings, SiteFooter, SiteHeader, SitePolicy, SiteSecurity, SiteSettings, SupportedUILanguages, SyntexModels, Tenant, TermGroups, Theme, WebApiPermissions, WebSettings, Workflows Supports multi language site collections.
Lists, Libraries (more possible but I only use it for that), with their Columns, Views, Custom Formatting (some basic list settings without permissions). Only takes one language.
When to use
When you want to copy complete site collections or single objects like lists or libraries that users interact with. Copying from one to another site collection
When you only want to copy basic lists or libraries, that users do not interact with. These lists or libraries are only “databases” for your Power Platform solution. Copying lists or libraries from one to another site collection
Caveats
Way more effort necessary than using rest. Requires an enterprise application registered in Entra ID Only for initial creation of objects, no updates possible
Only for initial creation of objects, no updates possible Copies lists, libraries and columns with their displaynames and not their internal names. This might break your flows or apps depending on your naming convention. Explanation: I usually build my lists and libraries that I use with Power Apps and Power Automate only using internal column names like qmsResubmissionDate instead of readable display names. If you were to copy the lists with this method using the displayname, you new list will have the previous displayname as the columns internal name. This might break your flows or apps.

PNP - PowerShell

💡

When-to-use-example You are building a solution on SharePoint, where the SharePoint interface is the primary system for your enduser. You might have Power Apps or Automate helping you out, but users interact with SharePoint directly. Therefore you have lists, libraries, terms, site columns, a structured navigation as well as a few default pages.

Check out the installation of the PNP-PowerShell here: https://pnp.github.io/powershell/articles/installation.html

Create a site template

This is not a complete script, it only supposed to show a rough guideline. For all possible parameters for the copy command, check out the CMDlet here: https://pnp.github.io/powershell/cmdlets/Get-PnPSiteTemplate.html

Pasting a site template

This is not a complete script, it only supposed to show a rough guideline. For all possible parameters for the paste command, check out the CMDlet here: https://pnp.github.io/powershell/cmdlets/Invoke-PnPSiteTemplate.html

Copy with REST API

I use Power Automate to achieve this easily.

💡

When-to-use-example You are building a solution in the Power Platform and you are using SharePoint lists or libraries as a database. User are never accessing the SharePoint site collection directly. They will always you the app or flows will process data in your lists and libraries. You are only using lists or libraries with list columns.

Feel free to check out the site design rest api here for some more information: https://learn.microsoft.com/en-us/sharepoint/dev/declarative-customization/site-design-rest-api

Copy a list

Looking at what the site design rest api is, you are basically creating a instructions on how to create the list with all its parameters. You can save those instruction into a JSON file. With the API call you request those instruction for one list at a time. If you have multiple lists, you will have to create a loop that appends each instruction JSON to an array. You can then save the array to a file and store it in a library somewhere.

Pasting a list

Pasting is only possible on another site collection, if a list with the same name already exists. The pasting process will be skipped. You could probably make a few adjustments to the instructions JSON to paste even into the same site collection, but I haven’t tried that so far.

Since you saved one instruction manual per list to your JSON file, you will also have to execute those instruction per list while pasting it into another site collection. The array you save into the JSON file can be used in an Apply to each loop, where you execute each instruction manual one by one.

I hope this helps as it helped me save a lot of time when developing Power Platform solution on SharePoint.

Thanks for reading! 💕

Logo

Events & slides

Buy me a snack

Contact form

Data privacy policy

About

This blog is made with ♥️ on Notion and made public with Super.so. Rocket icon created by RIkas Dzihab - Flaticon.

RedditLinkedIn
$exportsiteurl = Read-Host -Prompt "Export Site URL"
$ClientId = Read-Host -Prompt "Please enter the Client-Id"
$exportpath = "C:\temp\"

#Connect to the site collection you want to export from with the URL and the Client ID you got from the registration process
Connect-PnPOnline -Url $exportsiteurl -Interactive -ClientId $ClientId

#Depending on what you want to copy the command might vary. I always like to select only the lists I need, as the script doesnt need to extract hidden or default objects.
#This command will export only the two lists mentioned here with their IDs. It will create a .xml file with the lists information.
Get-PnPSiteTemplate -ListsToExtract "LIST 1 ID","LIST 2 ID" -Out $ExportFilePath -Verbose

#If you build a multi language enabled site collection, use the PersistMultiLanguageResources parameters. This will create a .resx file where language information is stored
Get-PnPSiteTemplate -PersistMultiLanguageResources -ListsToExtract "LIST 1 ID","LIST 2 ID" -IncludeAllPages -Out $ExportFilePath -Verbose
$ImportSiteUrl = Read-Host -Prompt "Import Site URL"
$ImportFolder = "C:\temp\Solution\"
$ImportFile = $importFolder +  "SolutionMain.xml"

#Connect to the site collection you want to import to with the URL and the Client ID you got from the registration process
Connect-PnPOnline -Url $ImportSiteUrl -Interactive -ClientId $ClientId

#If you want to completely apply the template to your new site collection, you can use this command
Invoke-PnPSiteTemplate -Path $ImportFile

#Usually I split up my template file into smaller pieces, as this help sometimes with performance. For example I will have multiple of those command importing different objects. You can specify the objects using the parameter for Handlers.
Invoke-PnPSiteTemplate -Path $ImportFile -Handlers TermGroups, Fields, ContentTypes

#If you have a multi language enabled site collection, you should use the parameter ResourceFolder to specify where you language files are stored. The command will automatically pick the correct ones to apply
Invoke-PnPSiteTemplate -Path $ImportFile -Handlers TermGroups, Fields, ContentTypes -ResourceFolder $ImportFolder
Method: POST
Uri: _api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteScriptFromList

Headers: 
{
  "accept": "application/json;odata=verbose",
  "content-type ": "application/json;odata=verbose"
}

Body: 
{
//for lists
"listUrl":"SITEURL/Lists/ListNameAsDisplayedInUrl"
//for libraries
"listUrl":"SITEURL/LibraryNameAsDisplayedInUrl"
}

Result:
//this is the result that you either store directly into the JSON file, or if you have multiple lists append to an array variable. Later you will then save that array variable into the JSON file
body('ACTIONNAME')?['d']?['GetSiteScriptFromList']
Method: POST
Uri: _api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.ExecuteTemplateScript()

Headers: 
{
  "accept": "application/json;odata=verbose",
  "content-type ": "application/json;odata=verbose"
}

Body: 
{
"script":"ResultsFromCopyAction"
}

Results: 
//An array of the past log, everything the past has done with error codes. If successful, the error code is 0.
body('ACTIONNAME')?['d']?['ExecuteTemplateScript']?['results']