Skip to content
This repository was archived by the owner on Jan 19, 2021. It is now read-only.

Commit 2040344

Browse files
committed
Added Export-PnPListToProvisioningTemplate
1 parent cd99148 commit 2040344

File tree

3 files changed

+287
-0
lines changed

3 files changed

+287
-0
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55

66
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
77

8+
## [3.11.]
9+
10+
### Added
11+
12+
- Added Export-PnPListToProvisioningTemplate cmdlet to export one or more lists to a provisioning template skipping all other artifacts.
13+
14+
15+
816
## [3.10.1906.0]
917

1018
### Added
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
using System;
2+
using System.IO;
3+
using System.Management.Automation;
4+
using Microsoft.SharePoint.Client;
5+
using OfficeDevPnP.Core.Framework.Provisioning.Connectors;
6+
using OfficeDevPnP.Core.Framework.Provisioning.Model;
7+
using OfficeDevPnP.Core.Framework.Provisioning.ObjectHandlers;
8+
using OfficeDevPnP.Core.Framework.Provisioning.Providers;
9+
using SharePointPnP.PowerShell.CmdletHelpAttributes;
10+
using OfficeDevPnP.Core.Framework.Provisioning.Providers.Xml;
11+
using File = System.IO.File;
12+
using Resources = SharePointPnP.PowerShell.Commands.Properties.Resources;
13+
using SharePointPnP.PowerShell.Commands.Utilities;
14+
using System.Collections.Generic;
15+
16+
namespace SharePointPnP.PowerShell.Commands.Provisioning.Site
17+
{
18+
[Cmdlet(VerbsData.Export, "PnPListToProvisioningTemplate", SupportsShouldProcess = true)]
19+
[CmdletHelp("Exports one or more lists to provisioning template",
20+
Category = CmdletHelpCategory.Provisioning)]
21+
[CmdletExample(
22+
Code = @"PS:> Export-PnPProvisioningTemplate -Out template.xml -List ""Documents""",
23+
Remarks = "Extracts a list to a new provisioning template including the list specified by title or ID.",
24+
SortOrder = 1)]
25+
[CmdletExample(
26+
Code = @"PS:> Export-PnPProvisioningTemplate -Out template.pnp -List ""Documents"",""Events""",
27+
Remarks = "Extracts a list to a new provisioning template Office Open XML file, including the lists specified by title or ID.",
28+
SortOrder = 2)]
29+
public class ExportListToProvisioningTemplate : PnPWebCmdlet
30+
{
31+
private ProgressRecord mainProgressRecord = new ProgressRecord(0, "Processing", "Status");
32+
private ProgressRecord subProgressRecord = new ProgressRecord(1, "Activity", "Status");
33+
34+
[Parameter(Mandatory = true, HelpMessage = "Specify the lists to extract, either providing their ID or their Title.")]
35+
public List<string> List;
36+
37+
[Parameter(Mandatory = false, Position = 0, HelpMessage = "Filename to write to, optionally including full path")]
38+
public string Out;
39+
40+
[Parameter(Mandatory = false, Position = 1, HelpMessage = "The schema of the output to use, defaults to the latest schema")]
41+
public XMLPnPSchemaVersion Schema = XMLPnPSchemaVersion.LATEST;
42+
43+
[Parameter(Mandatory = false, HelpMessage = "Overwrites the output file if it exists.")]
44+
public SwitchParameter Force;
45+
46+
[Parameter(Mandatory = false, HelpMessage = "Returns the template as an in-memory object, which is an instance of the ProvisioningTemplate type of the PnP Core Component. It cannot be used together with the -Out parameter.")]
47+
public SwitchParameter OutputInstance;
48+
49+
protected override void ExecuteCmdlet()
50+
{
51+
if (!string.IsNullOrEmpty(Out))
52+
{
53+
if (!Path.IsPathRooted(Out))
54+
{
55+
Out = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Out);
56+
}
57+
if (File.Exists(Out))
58+
{
59+
if (Force || ShouldContinue(string.Format(Resources.File0ExistsOverwrite, Out), Resources.Confirm))
60+
{
61+
ExtractTemplate(Schema, new FileInfo(Out).DirectoryName, new FileInfo(Out).Name);
62+
}
63+
}
64+
else
65+
{
66+
ExtractTemplate(Schema, new FileInfo(Out).DirectoryName, new FileInfo(Out).Name);
67+
}
68+
}
69+
else
70+
{
71+
ExtractTemplate(Schema, SessionState.Path.CurrentFileSystemLocation.Path, null);
72+
}
73+
}
74+
75+
private void ExtractTemplate(XMLPnPSchemaVersion schema, string path, string packageName)
76+
{
77+
SelectedWeb.EnsureProperty(w => w.Url);
78+
79+
var creationInformation = new ProvisioningTemplateCreationInformation(SelectedWeb);
80+
81+
creationInformation.HandlersToProcess = Handlers.Lists;
82+
83+
var extension = "";
84+
if (packageName != null)
85+
{
86+
if (packageName.IndexOf(".", StringComparison.Ordinal) > -1)
87+
{
88+
extension = packageName.Substring(packageName.LastIndexOf(".", StringComparison.Ordinal)).ToLower();
89+
}
90+
else
91+
{
92+
packageName += ".pnp";
93+
extension = ".pnp";
94+
}
95+
}
96+
97+
var fileSystemConnector = new FileSystemConnector(path, "");
98+
if (extension == ".pnp")
99+
{
100+
creationInformation.FileConnector = new OpenXMLConnector(packageName, fileSystemConnector);
101+
}
102+
else
103+
{
104+
creationInformation.FileConnector = fileSystemConnector;
105+
}
106+
107+
creationInformation.ProgressDelegate = (message, step, total) =>
108+
{
109+
var percentage = Convert.ToInt32((100 / Convert.ToDouble(total)) * Convert.ToDouble(step));
110+
111+
WriteProgress(new ProgressRecord(0, $"Extracting Template from {SelectedWeb.Url}", message) { PercentComplete = percentage });
112+
};
113+
creationInformation.MessagesDelegate = (message, type) =>
114+
{
115+
switch (type)
116+
{
117+
case ProvisioningMessageType.Warning:
118+
{
119+
WriteWarning(message);
120+
break;
121+
}
122+
case ProvisioningMessageType.Progress:
123+
{
124+
var activity = message;
125+
if (message.IndexOf("|") > -1)
126+
{
127+
var messageSplitted = message.Split('|');
128+
if (messageSplitted.Length == 4)
129+
{
130+
var current = double.Parse(messageSplitted[2]);
131+
var total = double.Parse(messageSplitted[3]);
132+
subProgressRecord.RecordType = ProgressRecordType.Processing;
133+
subProgressRecord.Activity = messageSplitted[0];
134+
subProgressRecord.StatusDescription = messageSplitted[1];
135+
subProgressRecord.PercentComplete = Convert.ToInt32((100 / total) * current);
136+
WriteProgress(subProgressRecord);
137+
}
138+
else
139+
{
140+
subProgressRecord.Activity = "Processing";
141+
subProgressRecord.RecordType = ProgressRecordType.Processing;
142+
subProgressRecord.StatusDescription = activity;
143+
subProgressRecord.PercentComplete = 0;
144+
WriteProgress(subProgressRecord);
145+
}
146+
}
147+
else
148+
{
149+
subProgressRecord.Activity = "Processing";
150+
subProgressRecord.RecordType = ProgressRecordType.Processing;
151+
subProgressRecord.StatusDescription = activity;
152+
subProgressRecord.PercentComplete = 0;
153+
WriteProgress(subProgressRecord);
154+
}
155+
break;
156+
}
157+
case ProvisioningMessageType.Completed:
158+
{
159+
WriteProgress(new ProgressRecord(1, message, " ") { RecordType = ProgressRecordType.Completed });
160+
break;
161+
}
162+
}
163+
};
164+
165+
if (List != null && List.Count > 0)
166+
{
167+
creationInformation.ListsToExtract.AddRange(List);
168+
}
169+
170+
var template = SelectedWeb.GetProvisioningTemplate(creationInformation);
171+
172+
173+
174+
if (!OutputInstance)
175+
{
176+
ITemplateFormatter formatter = null;
177+
switch (schema)
178+
{
179+
case XMLPnPSchemaVersion.LATEST:
180+
{
181+
formatter = XMLPnPSchemaFormatter.LatestFormatter;
182+
break;
183+
}
184+
case XMLPnPSchemaVersion.V201503:
185+
{
186+
#pragma warning disable CS0618 // Type or member is obsolete
187+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2015_03);
188+
#pragma warning restore CS0618 // Type or member is obsolete
189+
break;
190+
}
191+
case XMLPnPSchemaVersion.V201505:
192+
{
193+
#pragma warning disable CS0618 // Type or member is obsolete
194+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2015_05);
195+
#pragma warning restore CS0618 // Type or member is obsolete
196+
break;
197+
}
198+
case XMLPnPSchemaVersion.V201508:
199+
{
200+
#pragma warning disable CS0618 // Type or member is obsolete
201+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2015_08);
202+
#pragma warning restore CS0618 // Type or member is obsolete
203+
break;
204+
}
205+
case XMLPnPSchemaVersion.V201512:
206+
{
207+
#pragma warning disable CS0618 // Type or member is obsolete
208+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2015_12);
209+
#pragma warning restore CS0618 // Type or member is obsolete
210+
break;
211+
}
212+
case XMLPnPSchemaVersion.V201605:
213+
{
214+
#pragma warning disable CS0618 // Type or member is obsolete
215+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2016_05);
216+
#pragma warning restore CS0618 // Type or member is obsolete
217+
break;
218+
}
219+
case XMLPnPSchemaVersion.V201705:
220+
{
221+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2017_05);
222+
break;
223+
}
224+
case XMLPnPSchemaVersion.V201801:
225+
{
226+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2018_01);
227+
break;
228+
}
229+
case XMLPnPSchemaVersion.V201805:
230+
{
231+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2018_05);
232+
break;
233+
}
234+
case XMLPnPSchemaVersion.V201807:
235+
{
236+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2018_07);
237+
break;
238+
}
239+
case XMLPnPSchemaVersion.V201903:
240+
{
241+
formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2019_03);
242+
break;
243+
}
244+
}
245+
246+
if (extension == ".pnp")
247+
{
248+
IsolatedStorage.InitializeIsolatedStorage();
249+
250+
XMLTemplateProvider provider = new XMLOpenXMLTemplateProvider(
251+
creationInformation.FileConnector as OpenXMLConnector);
252+
var templateFileName = packageName.Substring(0, packageName.LastIndexOf(".", StringComparison.Ordinal)) + ".xml";
253+
254+
provider.SaveAs(template, templateFileName, formatter, null);
255+
}
256+
else
257+
{
258+
if (Out != null)
259+
{
260+
XMLTemplateProvider provider = new XMLFileSystemTemplateProvider(path, "");
261+
provider.SaveAs(template, Path.Combine(path, packageName), formatter, null);
262+
}
263+
else
264+
{
265+
var outputStream = formatter.ToFormattedTemplate(template);
266+
var reader = new StreamReader(outputStream);
267+
268+
WriteObject(reader.ReadToEnd());
269+
}
270+
}
271+
}
272+
else
273+
{
274+
WriteObject(template);
275+
}
276+
}
277+
}
278+
}

Commands/SharePointPnP.PowerShell.Commands.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@
637637
<Compile Include="Principals\RemoveAlert.cs" />
638638
<Compile Include="Principals\GetAlert.cs" />
639639
<Compile Include="Principals\AddAlert.cs" />
640+
<Compile Include="Provisioning\Site\ExportListToProvisioningTemplate.cs" />
640641
<Compile Include="Provisioning\Tenant\ApplyTenantTemplate.cs" />
641642
<Compile Include="Provisioning\Tenant\ReadTenantTemplate.cs" />
642643
<Compile Include="Provisioning\Tenant\SaveTenantTemplate.cs" />

0 commit comments

Comments
 (0)