Thursday, 25 November 2021

PowerShell Upload the list template to SharePoint Online List Template Gallery

#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"

$AppId =""
$AppSecret = ""   
   
#Function to Upload a list template To SharePoint Online using powershell
Function Upload-SPOListTemplate
{
    param
    (
        [string]$SiteURL  = $(throw "Enter the Site URL!"),
        [string]$ListTemplateName = $(throw "Enter the List Template Name!"),
        [string]$ListTemplateFile = $(throw "Enter the File Name to Upload List Template!")
    )
    Try {        
        #Setup Authentication Manager
        $AuthenticationManager = new-object OfficeDevPnP.Core.AuthenticationManager
        $Ctx = $AuthenticationManager.GetAppOnlyAuthenticatedContext($SiteUrl,$AppId,$AppSecret)
        $Ctx.Load($Ctx.Web)
        $Ctx.ExecuteQuery()
 
        Write-Host $Ctx.Web.Title
         
        #Get the "List Templates" Library
        $List= $Ctx.web.Lists.GetByTitle("List Template Gallery")
        $ListTemplates = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
        $Ctx.Load($ListTemplates)
        $Ctx.ExecuteQuery()
 
        #Check if the Given List Template already exists
        $ListTemplate = $ListTemplates | where { $_["TemplateTitle"] -eq $ListTemplateName }
 
        If($ListTemplate -eq $Null)
        {
            #Get the file from disk
            $FileStream = ([System.IO.FileInfo] (Get-Item $ListTemplateFile)).OpenRead()
            #Get File Name from source file path
            $TemplateFileName = Split-path $ListTemplateFile -leaf
    
            #Upload the File to SharePoint Library
            $FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
            $FileCreationInfo.Overwrite = $true
            $FileCreationInfo.ContentStream = $FileStream
            $FileCreationInfo.URL = $TemplateFileName
            $FileUploaded = $List.RootFolder.Files.Add($FileCreationInfo)
            $Ctx.Load($FileUploaded)
            $Ctx.ExecuteQuery()
             
            #Set Metadata of the File
            $ListItem = $FileUploaded.ListItemAllFields
            $Listitem["TemplateTitle"] = $ListTemplateName
            $Listitem["FileLeafRef"] = $ListTemplateName
            $ListItem.Update()
            $Ctx.ExecuteQuery()
  
            #Close file stream
            $FileStream.Close()
 
            write-host -f Green "List Template '$ListTemplateFile' Uploaded to $SiteURL"
        }
        else
        {
            Write-host -f Yellow "List Template '$ListTemplateName' Already Exists"
        }
    }
    Catch {
        write-host -f Red "Error Uploading List Template!" $_.Exception.Message
    }
}
 
#Variables
$SiteURL = ""   #Site collection URL
$ListTemplateName= "Projects Template V4"
$ListTemplateFile = "C:\Temp\CrescentProject.stp"
 
#Call the function to Upload the list template to SharePoint Online List Template Gallery
Upload-SPOListTemplate -SiteURL $SiteURL -ListTemplateName $ListTemplateName -ListTemplateFile $ListTemplateFile


 

PowerShell Save List as template and Download List Template to local folder

$AppId =""
$AppSecret = "" 


Function SaveListasTemplate {
    param
    (
        [string]$SiteURL  = $(throw "Enter the Site URL!"),
        [string]$ListName = $(throw "Enter the List Name!"),
        [string]$FileName = $(throw "Enter the List Template Name!"),
        [string]$TemplateName = $(throw "Enter the List Template Name!"),
        [string]$Description = $(throw "Enter the List Description Info!"),
        [string]$IncludeData= $(throw "List content include or not!")
    )
    Try{
        #Get Credentials to connect
        #$Cred= Get-Credential
       
        #Setup the context
        #$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
        #$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password)
        
        #Setup Authentication Manager
        $AuthenticationManager = new-object OfficeDevPnP.Core.AuthenticationManager
        $Ctx = $AuthenticationManager.GetAppOnlyAuthenticatedContext($SiteUrl,$AppId,$AppSecret)
        $Ctx.Load($Ctx.Web)
        $Ctx.ExecuteQuery()
 
        Write-Host $Ctx.Web.Title

        #Get the List
        $List = $Ctx.Web.lists.GetByTitle($ListName)
        $List.SaveAsTemplate($FileName, $TemplateName, $Description, $IncludeData)
        $Ctx.ExecuteQuery()
     
        Write-Host -f Green "List Saved as Template!"
    }
    Catch {
            write-host -f Red "Error Saving List as template!" $_.Exception.Message
    }
}

Function pnp_SaveListasTemplate {
    param
    (
        [string]$SiteURL  = $(throw "Enter the Site URL!"),
        [string]$ListName = $(throw "Enter the List Name!"),
        [string]$FileName = $(throw "Enter the List Template Name!"),
        [string]$TemplateName = $(throw "Enter the List Template Name!"),
        [string]$Description = $(throw "Enter the List Description Info!"),
        [string]$IncludeData= $(throw "List content include or not!")
    )
    Try{
        #Connect to PnP Online
        Connect-PnPOnline -Url $SiteURL -ClientId $AppId -ClientSecret $AppSecret 
        $Context  = Get-PnPContext
 
        #Get the List
        $List = Get-PnpList -Identity $ListName
 
        #Save List as template
        $List.SaveAsTemplate($TemplateFileName, $TemplateName, $TemplateDescription, $IncludeData)
        $Context.ExecuteQuery()

        Write-Host -f Green "List Saved as Template!"
    }
    Catch {
            write-host -f Red "Error Saving List as template!" $_.Exception.Message
    }
}

#Function to download a list template from SharePoint Online using powershell

Function Download_SPOListTemplate
{
    param
    (
        [string]$SiteURL  = $(throw "Enter the Site URL!"),
        [string]$ListTemplateName = $(throw "Enter the List Template Name!"),
        [string]$ExportFile = $(throw "Enter the File Name to Export List Template!")
    )
    Try {
        #Get Credentials to connect
        #Setup Authentication Manager
        $AuthenticationManager = new-object OfficeDevPnP.Core.AuthenticationManager
        $Ctx = $AuthenticationManager.GetAppOnlyAuthenticatedContext($SiteUrl,$AppId,$AppSecret)
         
        #Get the "List Templates" Library
        $List= $Ctx.web.Lists.GetByTitle("List Template Gallery")
        $ListTemplates = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
        $Ctx.Load($ListTemplates)
        $Ctx.ExecuteQuery()
 
        #Filter and get given List Template
        $ListTemplate = $ListTemplates | Where-Object { $_["TemplateTitle"] -eq $ListTemplateName }
 
        If($Null -ne $ListTemplate)
        {
            #Get the File from the List item
            $Ctx.Load($ListTemplate.File)
            $Ctx.ExecuteQuery()
 
            #Download the list template
            $FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($Ctx,$ListTemplate.File.ServerRelativeUrl)
            $WriteStream = [System.IO.File]::Open($ExportFile,[System.IO.FileMode]::Create)
            $FileInfo.Stream.CopyTo($WriteStream)
            $WriteStream.Close()
 
            write-host -f Green "List Template Downloaded to $ExportFile!" $_.Exception.Message
        }
        else
        {
            Write-host -f Yellow "List Template Not Found:"$ListTemplateName
        }
    }
    Catch {
        write-host -f Red "Error Downloading List Template!" $_.Exception.Message
    }
}


$SiteURL = ""
$ListName="PSTestLibrary" 
#Configure Save list as template parameters
$FileName="PSTestLibrary Template"
$TemplateName="PSTestLibrary Template"
$Description ="List Template for PSTestLibrary"
$IncludeData = $False
$ExportFile = "C:\Temp\" + $ListName + ".stp"
SaveListasTemplate -SiteURL $SiteURL -ListName $listName -FileName $fileName -TemplateName $templateName -Description $description -IncludeData $include

#Call the function to Download the list template
Download_SPOListTemplate -SiteURL $SiteURL -ListTemplateName $TemplateName -ExportFile $ExportFile

Sunday, 21 November 2021

PowerShell to Copy Document Libraries from One Site to Another Site Collection in SharePoint Online

In a migration project, I have a requirement to copy all document libraries from one site collection to another. Here is the PowerShell script I’ve used to copy all libraries (just the library without its actual content) between site collections:


#Parameters
$SourceSiteURL = "https://crescent.sharepoint.com/sites/Neoma"
$DestinationSiteURL = "https://crescent.sharepoint.com/sites/Neoma-Copy"
 
#Connect to the source Site
Connect-PnPOnline -URL $SourceSiteURL -Interactive
 
#Get all document libraries
$SourceLibraries Get-PnPList | Where {$_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $False}
 
#Connect to the destination site
Connect-PnPOnline -URL $DestinationSiteURL -Interactive
 
#Get All Lists in the Destination
$Libraries = Get-PnPList
 
ForEach($Library in $SourceLibraries)
{
    #Check if the library already exists in target
    If(!($Libraries.Title -contains $Library.Title))
    {
        #Create a document library
        New-PnPList -Title $Library.Title -Template DocumentLibrary
        Write-host "Document Library '$($Library.Title)' created successfully!" -f Green
    }
    else
    {
        Write-host "Document Library '$($Library.Title)' exists already!" -f Yellow
    }
}
SharePoint Online: PowerShell to Copy Libraries with its Content Between Sites

This time, let’s copy all document libraries along with its contents (Files, Folders, Sub-folders, etc.) of the document libraries to another site collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#Parameters
$SourceSiteURL = "https://crescent.sharepoint.com/sites/Marketing"
$DestinationSiteURL = "https://crescent.sharepoint.com/sites/Branding"
 
#Connect to the source Site
Connect-PnPOnline -URL $SourceSiteURL -Interactive
 
#Get all document libraries
$SourceLibraries Get-PnPList -Includes RootFolder | Where {$_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $False}
 
#Connect to the destination site
Connect-PnPOnline -URL $DestinationSiteURL -Interactive
 
#Get All Lists in the Destination site
$DestinationLibraries = Get-PnPList
 
ForEach($SourceLibrary in $SourceLibraries)
{
    #Check if the library already exists in target
    If(!($DestinationLibraries.Title -contains $SourceLibrary.Title))
    {
        #Create a document library
        $NewLibrary  = New-PnPList -Title $SourceLibrary.Title -Template DocumentLibrary
        Write-host "Document Library '$($SourceLibrary.Title)' created successfully!" -f Green
    }
    else
    {
        Write-host "Document Library '$($SourceLibrary.Title)' already exists!" -f Yellow
    }
 
    #Get the Destination Library
    $DestinationLibrary = Get-PnPList $SourceLibrary.Title -Includes RootFolder
    $SourceLibraryURL = $SourceLibrary.RootFolder.ServerRelativeUrl
    $DestinationLibraryURL = $DestinationLibrary.RootFolder.ServerRelativeUrl
 
    #Copy All Content from Source Library to Destination library
    Copy-PnPFile -SourceUrl $SourceLibraryURL -TargetUrl $DestinationLibraryURL -SkipSourceFolderName -Force -OverwriteIfAlreadyExists
    Write-host "`tContent Copied from $SourceLibraryURL to  $DestinationLibraryURL Successfully!" -f Green
}

The above script works perfectly fine with simple document libraries. However, What if your document library has custom metadata columns added to it? What if you want to copy document libraries along with its custom settings? Well, here is the PowerShell script that uses creating list template and list instances method to copy document library in SharePoint Online!
PowerShell to Copy Document Libraries Between Site Collections in SharePoint Online

This PowerShell script copies lists along with their settings and metadata columns to the destination site.

Make sure you have enabled custom script in SharePoint Online prior running this script! Otherwise, you’ll end up in error “Access denied. You do not have permission to perform this action or access this resource.” How to Enable Custom Script in SharePoint Online?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#Function to Copy All libraries from One Site to another
Function Copy-PnPAllLibraries
{
    param (
    [parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$SourceSiteURL,
    [parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$DestinationSiteURL
    )
 
    Try {
    #Connect to the Source Site and Get the List Templates
    $SourceConn = Connect-PnPOnline -URL $SourceSiteURL -Interactive -ReturnConnection
    $SourceCtx = $SourceConn.Context
    $SourceRootWeb = $SourceCtx.Site.RootWeb
    $SourceListTemplates = $SourceCtx.Site.GetCustomListTemplates($SourceRootWeb)
    $SourceCtx.Load($SourceRootWeb)
    $SourceCtx.Load($SourceListTemplates)
    $SourceCtx.ExecuteQuery()
 
    #Connect to the Destination Site and Get the List Templates
    $DestinationConn = Connect-PnPOnline -URL $DestinationSiteURL -Interactive -ReturnConnection
    $DestinationCtx = $DestinationConn.Context
    $DestinationRootWeb = $DestinationCtx.Site.RootWeb
    $DestinationListTemplates = $DestinationCtx.Site.GetCustomListTemplates($DestinationRootWeb)
    $DestinationCtx.Load($DestinationRootWeb)
    $DestinationCtx.Load($DestinationListTemplates)
    $DestinationCtx.ExecuteQuery()
 
    #Exclude certain libraries
    $ExcludedLibraries =  @("Style Library","Preservation Hold Library", "Site Pages", "Site Assets","Form Templates", "Site Collection Images","Site Collection Documents")
     
    #Get Libraries from Source site - Skip hidden and certain libraries
    $SourceLibraries Get-PnPList -Includes RootFolder -Connection $SourceConn | Where {$_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $False -and $_.Title -notin $ExcludedLibraries}
 
    #Iterate through each library in the source
    ForEach($SourceLibrary in $SourceLibraries)
    {
        Write-host "Copying library:"$SourceLibrary.Title -f Green
 
        #Remove the List template if exists
        $SourceListTemplate = $SourceListTemplates | Where {$_.Name -eq $SourceLibrary.id.Guid}
        $SourceListTemplateURL = $SourceRootWeb.ServerRelativeUrl+"/_catalogs/lt/"+$SourceLibrary.id.Guid+".stp"
        If($SourceListTemplate)
        {
            Remove-PnPFile -ServerRelativeUrl $SourceListTemplateURL -Recycle -Force -Connection $SourceConn
        }
        Write-host "Creating List Template from Source Library..." -f Yellow -NoNewline
        $SourceLibrary.SaveAsTemplate($SourceLibrary.id.Guid, $SourceLibrary.id.Guid, [string]::Empty, $False)
        $SourceCtx.ExecuteQuery()
        Write-host "Done!" -f Green
 
        #Reload List Templates to Get Newly created List Template
        $SourceListTemplates = $SourceCtx.Site.GetCustomListTemplates($SourceRootWeb)
        $SourceCtx.Load($SourceListTemplates)
        $SourceCtx.ExecuteQuery()
        $SourceListTemplate = $SourceListTemplates | Where {$_.Name -eq $SourceLibrary.id.Guid}
 
        #Remove the List template if exists in destination
        $DestinationListTemplate = $DestinationListTemplates | Where {$_.Name -eq $SourceLibrary.id.Guid}
        $DestinationListTemplateURL = $DestinationRootWeb.ServerRelativeUrl+"/_catalogs/lt/"+$SourceLibrary.id.Guid+".stp"
        If($DestinationListTemplate)
        {
            Remove-PnPFile -ServerRelativeUrl $DestinationListTemplateURL -Recycle -Force -Connection $DestinationConn
        }
 
        #Copy List Template from source to the destination site
        Write-host "Copying List Template from Source to Destination Site..." -f Yellow -NoNewline
        Copy-PnPFile -SourceUrl $SourceListTemplateURL -TargetUrl $DestinationListTemplateURL -SkipSourceFolderName -Force -OverwriteIfAlreadyExists
        Write-host "Done!" -f Green
 
        #Reload List Templates to Get Newly created List Template
        $DestinationListTemplates = $DestinationCtx.Site.GetCustomListTemplates($DestinationRootWeb)
        $DestinationCtx.Load($DestinationListTemplates)
        $DestinationCtx.ExecuteQuery()
        $DestinationListTemplate = $DestinationListTemplates | Where {$_.Name -eq $SourceLibrary.id.Guid}
 
        #Create the destination library from the list template
        Write-host "Creating New Library in the Destination Site..." -f Yellow -NoNewline
        If(!(Get-PnPList -Identity $SourceLibrary.Title -Connection $DestinationConn))
        {
            #Create the destination library
            $ListCreation = New-Object Microsoft.SharePoint.Client.ListCreationInformation
            $ListCreation.Title = $SourceLibrary.Title
            $ListCreation.ListTemplate = $DestinationListTemplate
            $DestinationList = $DestinationCtx.Web.Lists.Add($ListCreation)
            $DestinationCtx.ExecuteQuery()
            Write-host "Library '$($SourceLibrary.Title)' created successfully!" -f Green
        }
        Else
        {
            Write-host "Library '$($SourceLibrary.Title)' already exists!" -f Yellow
        }
     
        #Copy content from Source to destination library
        $SourceLibraryURL = $SourceLibrary.RootFolder.ServerRelativeUrl
        $DestinationLibrary = Get-PnPList $SourceLibrary.Title -Includes RootFolder -Connection $DestinationConn
        $DestinationLibraryURL = $DestinationLibrary.RootFolder.ServerRelativeUrl
        Write-host "`Copying Content from $SourceLibraryURL to $DestinationLibraryURL..." -f Yellow -NoNewline
 
        #Copy All Content from Source Library to the Destination Library
        Copy-PnPFile -SourceUrl $SourceLibraryURL -TargetUrl $DestinationLibraryURL -SkipSourceFolderName -Force -OverwriteIfAlreadyExists
        Write-host "`tContent Copied Successfully!" -f Green
 
        #Cleanup List Templates in source and destination sites
        Remove-PnPFile -ServerRelativeUrl $SourceListTemplateURL -Recycle -Force -Connection $SourceConn
        Remove-PnPFile -ServerRelativeUrl $DestinationListTemplateURL -Recycle -Force -Connection $DestinationConn
        }
    }
    Catch {
        write-host -f Red "Error:" $_.Exception.Message
    }
}
 
#Parameters
$SourceSiteURL = "https://crescent.sharepoint.com/sites/Marketing"
$DestinationSiteURL = "https://crescent.sharepoint.com/sites/HR"
 
#Call the function to copy libraries to another site
Copy-PnPAllLibraries -SourceSiteURL $SourceSiteURL -DestinationSiteURL $DestinationSiteURL