Feb 13 2017 08:53 AM
Hi
Is it possible to create a pnp provisioning file with a folder structure for a library by using Convert-PnPFolderToProvisioningTemplate or doesn't the current provisioning enging support pnp packages with folders? I have tried with several options but with no success.
I would like the whole package to contain the folders from the beginning avoiding to have to handle that separately when the template has been applied to the site.
/Niclas
Feb 13 2017 11:33 PM
Feb 14 2017 09:24 AM
You could create a extention in your template and use this code:
Snippet
private void CreateFolders(ClientContext context, Web web, List list, Project.Provisioning.Models.ListConfigurationListFolder[] folders) { foreach (var folder in folders) { ListItem newItem; try { // Create folder ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation(); itemCreateInfo.UnderlyingObjectType = FileSystemObjectType.Folder; itemCreateInfo.LeafName = folder.Title; newItem = list.AddItem(itemCreateInfo); newItem["Title"] = folder.Title; newItem.Update(); context.ExecuteQueryRetry(); } catch (Exception e) { TraceHelper.WriteInformationToListener("LogFile", $"Couldn't create folder: {folder.Title}."); continue; } if (folder.ObjectSecurity != null) { // Set item security var securitySettings = folder.ObjectSecurity.BreakRoleInheritance; if (securitySettings.RoleAssignment.Length == 0) continue; try { var groups = context.LoadQuery(context.Web.SiteGroups.Include(g => g.LoginName)); var webRoleDefinitions = context.LoadQuery(context.Web.RoleDefinitions); context.ExecuteQueryRetry(); newItem.BreakRoleInheritance(securitySettings.CopyRoleAssignments, securitySettings.ClearSubscopes); foreach (var roleAssignment in securitySettings.RoleAssignment) { Principal principal = groups.FirstOrDefault(g => g.LoginName == roleAssignment.Principal); if (principal == null) { principal = context.Web.EnsureUser(roleAssignment.Principal); } var roleDefinitionBindingCollection = new RoleDefinitionBindingCollection(context); var roleDefinition = webRoleDefinitions.FirstOrDefault(r => r.Name == roleAssignment.RoleDefinition); if (roleDefinition != null) { roleDefinitionBindingCollection.Add(roleDefinition); } newItem.RoleAssignments.Add(principal, roleDefinitionBindingCollection); } context.ExecuteQueryRetry(); } catch (Exception e) { TraceHelper.WriteInformationToListener("LogFile", "Error occured when setting itemlevel security on folder."); continue; } } } }
Feb 19 2017 05:12 AM
Hi Paul
What would the provisioning Template entries look like to support the folder hierarchy?
Regards
Nigel
Feb 19 2017 11:18 PM
hi Nigel,
in my code i did a big one this is a extract of the template:
<def:ListConfiguration xmlns:def="http://tempuri.org/ListConfiguration"> <def:SiteUrl>{parameter:SiteCollectionUrl}</def:SiteUrl> <def:Lists> <def:List Url="COM"> <def:Folders> <def:Folder Title="Estimates"> <def:ObjectSecurity> <def:BreakRoleInheritance ClearSubscopes="false" CopyRoleAssignments="true"> <def:RoleAssignment Principal="Estimators" RoleDefinition="ContributeWithoutDelete"/> </def:BreakRoleInheritance> </def:ObjectSecurity> </def:Folder> </def:Folders> </def:List> </def:Lists> </def:ListConfiguration>
Feb 20 2017 02:21 AM
Thanks Paul - very interesting - I will have to give it a go. I have been looking to be able to this for a while. Should there not be something in the pnp provisioning template which links your <def:... to your code ?
Feb 20 2017 08:10 AM
Hi
I have used the sample ProvisioningSchema-2016-05-DirectorySample.xml provided here and it doesn't seem like the Convert-PnPFolderToProvisioningTemplate take the files in consideration when the package is made. I have referenced the files like this in the xml file.
<pnp:Files> <pnp:Directory src="c:\temp\DirectoryBulkLoadSample" Folder="BulkLoaded" Overwrite="true" Recursive="true" IncludedExtensions="*.docx,*.pdf" ExcludedExtensions="*.xml,*.txt" MetadataMappingFile="c:\BulkLoadedMetadata.json" /> </pnp:Files>
Feb 20 2017 08:11 AM
Yep I guess that I have to look at a custom extension. Too bad as it would have been nice if the Convert-PnPFolderToProvisioningTemplate command had packaged the files and folders in the same pnp package.
/Niclas
Feb 22 2017 12:37 PM
Hi Paul
@ErwinVanHunen's Blog says this is the call you make for the extension ->
public void ProcessRequest(ClientContext ctx, ProvisioningTemplate template, string configurationData)
Your code has this ->
private void CreateFolders(ClientContext context, Web web, List list, Project.Provisioning.Models.ListConfigurationListFolder[] folders)
So I presume I have to convert between the two.
I can get web from the clientcontext but for the list I need to have the list name. Where do I get that from ?
Thanks
Nigel