I’ve been doing a lot with variations recently and have encountered numerous challenges with keeping data and lists in sync between the various variations. One of the things that we ended up implementing on my current project was a simple event receiver which copied items from one variation to another when that item was approved. From this you can obviously conclude that we had matching lists in each variation. One of the challenges with this was keeping the security on the lists the same between each of the variations and being able to set that security without being able to read the menus of the site (the other variation was in Korean).
So what I decided to create was a simple command that that would enable me to export the security of a list to an XML file. Once I had the XML I could then create an import command which would allow me to set the security on the lists in the other variations or even in other farms so I could get it set in our test farm and then import to production. The first command I created is called, simply enough, gl-exportlistsecurity
. I’ll talk about the import command in a follow up post.
Creating this command was actually really easy because I already had a command which would copy the security settings of a source list to a destination list. I could have obviously used this command in a single farm only environment but I wanted the ability to set the security in a test farm and import to the production farm so my gl-copylistsecurity
command wouldn’t really work for me. The code also exports folder level and optionally item level security. The code can be seen below:
1/// <summary>
2/// Exports the security.
3/// </summary>
4/// <param name="outputFile">The output file.</param>
5/// <param name="scope">The scope.</param>
6/// <param name="url">The URL.</param>
7/// <param name="includeItemSecurity">if set to <c>true</c> [include item security].</param>
8public static void ExportSecurity(string outputFile, string scope, string url, bool includeItemSecurity)
9{
10 using (SPSite site = new SPSite(url))
11 using (SPWeb web = site.OpenWeb())
12 {
13 StringBuilder sb = new StringBuilder();
14
15 XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(sb));
16 xmlWriter.Formatting = Formatting.Indented;
17
18 Log("Start Time: {0}.", DateTime.Now.ToString());
19
20
21 if (scope == "list")
22 {
23 SPList list = Utilities.GetListFromViewUrl(web, url);
24
25 if (list == null)
26 throw new SPException("List was not found.");
27 ExportSecurity(list, web, xmlWriter, includeItemSecurity);
28 }
29 else
30 {
31 xmlWriter.WriteStartElement("Lists");
32 foreach (SPList list in web.Lists)
33 {
34 ExportSecurity(list, web, xmlWriter, includeItemSecurity);
35 }
36 xmlWriter.WriteEndElement(); //Lists
37 }
38 xmlWriter.Flush();
39
40 File.WriteAllText(outputFile, sb.ToString());
41
42 Log("Finish Time: {0}.\r\n", DateTime.Now.ToString());
43
44 }
45}
46
47/// <summary>
48/// Exports the security.
49/// </summary>
50/// <param name="list">The list.</param>
51/// <param name="web">The web.</param>
52/// <param name="xmlWriter">The XML writer.</param>
53/// <param name="includeItemSecurity">if set to <c>true</c> [include item security].</param>
54public static void ExportSecurity(SPList list, SPWeb web, XmlTextWriter xmlWriter, bool includeItemSecurity)
55{
56 try
57 {
58 Log("Progress: Processing list \"{0}\".", list.RootFolder.ServerRelativeUrl);
59
60 xmlWriter.WriteStartElement("List");
61 xmlWriter.WriteAttributeString("WriteSecurity", list.WriteSecurity.ToString());
62 xmlWriter.WriteAttributeString("ReadSecurity", list.ReadSecurity.ToString());
63 xmlWriter.WriteAttributeString("Url", list.RootFolder.Url);
64
65 // Write the security for the list itself.
66 WriteObjectSecurity(list, xmlWriter);
67
68 // Write the security for any folders in the list.
69 WriteFolderSecurity(list, xmlWriter);
70
71 // Write the security for any items in the list.
72 if (includeItemSecurity)
73 WriteItemSecurity(list, xmlWriter);
74
75 xmlWriter.WriteEndElement(); // List
76 }
77 finally
78 {
79 Log("Progress: Finished processing list \"{0}\".", list.RootFolder.ServerRelativeUrl);
80 }
81}
82
83/// <summary>
84/// Writes the folder security.
85/// </summary>
86/// <param name="list">The list.</param>
87/// <param name="xmlWriter">The XML writer.</param>
88public static void WriteFolderSecurity(SPList list, XmlTextWriter xmlWriter)
89{
90 foreach (SPListItem folder in list.Folders)
91 {
92 Log("Progress: Processing folder \"{0}\".", folder.Url);
93
94 xmlWriter.WriteStartElement("Folder");
95 xmlWriter.WriteAttributeString("Url", folder.Url);
96 WriteObjectSecurity(folder, xmlWriter);
97 xmlWriter.WriteEndElement(); // Folder
98 }
99}
100
101/// <summary>
102/// Writes the item security.
103/// </summary>
104/// <param name="list">The list.</param>
105/// <param name="xmlWriter">The XML writer.</param>
106public static void WriteItemSecurity(SPList list, XmlTextWriter xmlWriter)
107{
108 foreach (SPListItem item in list.Items)
109 {
110 Log("Progress: Processing item \"{0}\".", item.ID.ToString());
111
112 xmlWriter.WriteStartElement("Item");
113 xmlWriter.WriteAttributeString("Id", item.ID.ToString());
114 WriteObjectSecurity(item, xmlWriter);
115 xmlWriter.WriteEndElement(); // Item
116 }
117}
118
119/// <summary>
120/// Writes the object security.
121/// </summary>
122/// <param name="sourceObject">The source object.</param>
123/// <param name="xmlWriter">The XML writer.</param>
124public static void WriteObjectSecurity(ISecurableObject sourceObject, XmlTextWriter xmlWriter)
125{
126 xmlWriter.WriteAttributeString("HasUniqueRoleAssignments", sourceObject.HasUniqueRoleAssignments.ToString());
127
128 if (!sourceObject.HasUniqueRoleAssignments)
129 return;
130
131 //xmlWriter.WriteRaw(sourceObject.RoleAssignments.Xml);
132
133 xmlWriter.WriteStartElement("RoleAssignments");
134 foreach (SPRoleAssignment ra in sourceObject.RoleAssignments)
135 {
136 xmlWriter.WriteStartElement("RoleAssignment");
137 xmlWriter.WriteAttributeString("Member", ra.Member.Name);
138 SPPrincipalType pType = SPPrincipalType.None;
139 if (ra.Member is SPUser)
140 pType = SPPrincipalType.User;
141 else if (ra.Member is SPGroup)
142 pType = SPPrincipalType.SharePointGroup;
143
144 xmlWriter.WriteAttributeString("PrincipalType", pType.ToString());
145
146 xmlWriter.WriteStartElement("RoleDefinitionBindings");
147 foreach (SPRoleDefinition rd in ra.RoleDefinitionBindings)
148 {
149 if (rd.Name == "Limited Access")
150 continue;
151
152 xmlWriter.WriteStartElement("RoleDefinition");
153 xmlWriter.WriteAttributeString("Name", rd.Name);
154 xmlWriter.WriteAttributeString("Description", rd.Description);
155 xmlWriter.WriteAttributeString("Order", rd.Order.ToString());
156 xmlWriter.WriteAttributeString("BasePermissions", rd.BasePermissions.ToString());
157 xmlWriter.WriteEndElement(); //RoleDefinition
158 }
159 xmlWriter.WriteEndElement(); //RoleDefinitionBindings
160 xmlWriter.WriteEndElement(); //RoleAssignment
161 }
162 xmlWriter.WriteEndElement(); //RoleAssignments
163}
The syntax of the command can be seen below:
C:\>stsadm -help gl-exportlistsecurity
stsadm -o gl-exportlistsecurity
Exports a list's security settings to an XML file.
Parameters:
-url <list view url to export security from>
-outputfile <file to output settings to>
-scope <Web | List>
[-quiet]
[-includeitemsecurity]
The following table summarizes the command and its various parameters:
Command Name | Availability | Build Date |
---|---|---|
gl-exportlistsecurity | WSS v3, MOSS 2007 | Released: 4/12/2008, Updated: 8/28/2008 |
Parameter Name | Short Form | Required | Description | Example Usage |
---|---|---|---|---|
scope | s | Yes | Either web or list. If web then the security for each list within the web will be exported. Note that this does not work recursively – only the lists in the specified web will be exported. | -scope web , -s web |
url | Yes | The URL to either a specific list (if scope is list) or to a web if scope is web. | -url http://portal | |
outputfile | file | Yes | The output path to save the results to. Must be a valid filename. | -outputfile "c:\security.xml" , -file "c:\security.xml" |
quiet | No | If specified then progress information will not be output to the console. | -quiet | |
-includeitemsecurity | items | No | If specified then item level security will be exported. | -includeitemsecurity , -items |
Here’s an example of using the command to export the security settings on the Documents library which is set to inherit security:
stsadm -o gl-exportlistsecurity -url http://portal/documents/forms/allitems.aspx -outputfile c:\security.xml -scope list
The output from running the above command would be something like (note that the list contained two folders, each inheriting as well):
1<List WriteSecurity="1" ReadSecurity="1" Url="Documents" HasUniqueRoleAssignments="False">
2 <Folder Url="Documents/Test Folder 1" HasUniqueRoleAssignments="False" />
3 <Folder Url="Documents/Test Folder 1/Test Folder 1" HasUniqueRoleAssignments="False" />
4</List>
If we change the list so that it no longer inherits it’s security and re-run the command we’d get results similar to the following:
1<List WriteSecurity="1" ReadSecurity="1" Url="Documents" HasUniqueRoleAssignments="True">
2 <RoleAssignments>
3 <RoleAssignment Member="SharePoint Administrator" PrincipalType="User">
4 <RoleDefinitionBindings />
5 </RoleAssignment>
6 <RoleAssignment Member="Home Owners" PrincipalType="SharePointGroup">
7 <RoleDefinitionBindings>
8 <RoleDefinition Name="Full Control" Description="Has full control." Order="1" BasePermissions="FullMask" />
9 </RoleDefinitionBindings>
10 </RoleAssignment>
11 <RoleAssignment Member="Home Visitors" PrincipalType="SharePointGroup">
12 <RoleDefinitionBindings>
13 <RoleDefinition Name="Read" Description="Can view only." Order="6" BasePermissions="ViewListItems, OpenItems, ViewVersions, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseUserInfo, UseClientIntegration, UseRemoteAPIs, CreateAlerts" />
14 </RoleDefinitionBindings>
15 </RoleAssignment>
16 <RoleAssignment Member="Home Members" PrincipalType="SharePointGroup">
17 <RoleDefinitionBindings>
18 <RoleDefinition Name="Contribute" Description="Can view, add, update, and delete." Order="5" BasePermissions="ViewListItems, AddListItems, EditListItems, DeleteListItems, OpenItems, ViewVersions, DeleteVersions, ManagePersonalViews, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, UseClientIntegration, UseRemoteAPIs, CreateAlerts, EditMyUserInfo" />
19 </RoleDefinitionBindings>
20 </RoleAssignment>
21 <RoleAssignment Member="Style Resource Readers" PrincipalType="SharePointGroup">
22 <RoleDefinitionBindings />
23 </RoleAssignment>
24 <RoleAssignment Member="Designers" PrincipalType="SharePointGroup">
25 <RoleDefinitionBindings>
26 <RoleDefinition Name="Design" Description="Can view, add, update, delete, approve, and customize." Order="2" BasePermissions="ViewListItems, AddListItems, EditListItems, DeleteListItems, ApproveItems, OpenItems, ViewVersions, DeleteVersions, CancelCheckout, ManagePersonalViews, ManageLists, ViewFormPages, Open, ViewPages, AddAndCustomizePages, ApplyThemeAndBorder, ApplyStyleSheets, CreateSSCSite, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, UseClientIntegration, UseRemoteAPIs, CreateAlerts, EditMyUserInfo" />
27 </RoleDefinitionBindings>
28 </RoleAssignment>
29 <RoleAssignment Member="Hierarchy Managers" PrincipalType="SharePointGroup">
30 <RoleDefinitionBindings>
31 <RoleDefinition Name="Manage Hierarchy" Description="Can create sites and edit pages, list items, and documents." Order="3" BasePermissions="ViewListItems, AddListItems, EditListItems, DeleteListItems, OpenItems, ViewVersions, DeleteVersions, CancelCheckout, ManagePersonalViews, ManageLists, ViewFormPages, Open, ViewPages, AddAndCustomizePages, ViewUsageData, CreateSSCSite, ManageSubwebs, ManagePermissions, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, ManageWeb, UseClientIntegration, UseRemoteAPIs, ManageAlerts, CreateAlerts, EditMyUserInfo, EnumeratePermissions" />
32 </RoleDefinitionBindings>
33 </RoleAssignment>
34 <RoleAssignment Member="Approvers" PrincipalType="SharePointGroup">
35 <RoleDefinitionBindings>
36 <RoleDefinition Name="Approve" Description="Can edit and approve pages, list items, and documents." Order="4" BasePermissions="ViewListItems, AddListItems, EditListItems, DeleteListItems, ApproveItems, OpenItems, ViewVersions, DeleteVersions, CancelCheckout, ManagePersonalViews, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseDirectories, BrowseUserInfo, AddDelPrivateWebParts, UpdatePersonalWebParts, UseClientIntegration, UseRemoteAPIs, CreateAlerts, EditMyUserInfo" />
37 </RoleDefinitionBindings>
38 </RoleAssignment>
39 <RoleAssignment Member="Restricted Readers" PrincipalType="SharePointGroup">
40 <RoleDefinitionBindings>
41 <RoleDefinition Name="Restricted Read" Description="Can view pages and documents, but cannot view historical versions or review user rights information." Order="7" BasePermissions="ViewListItems, OpenItems, Open, ViewPages" />
42 </RoleDefinitionBindings>
43 </RoleAssignment>
44 <RoleAssignment Member="Quick Deploy Users" PrincipalType="SharePointGroup">
45 <RoleDefinitionBindings />
46 </RoleAssignment>
47 <RoleAssignment Member="Viewers" PrincipalType="SharePointGroup">
48 <RoleDefinitionBindings>
49 <RoleDefinition Name="View Only" Description="Members of this group can view pages, list items, and documents. If the document has a server-side file handler available, they can only view the document using the server-side file handler." Order="2147483647" BasePermissions="ViewListItems, ViewVersions, ViewFormPages, Open, ViewPages, CreateSSCSite, BrowseUserInfo, UseClientIntegration, UseRemoteAPIs, CreateAlerts" />
50 </RoleDefinitionBindings>
51 </RoleAssignment>
52 </RoleAssignments>
53 <Folder Url="Documents/Test Folder 1" HasUniqueRoleAssignments="False" />
54 <Folder Url="Documents/Test Folder 1/Test Folder 1" HasUniqueRoleAssignments="False" />
55</List>
You may have noticed that I provide lots of details for the role definition bindings – this is so that I can recreate the bindings in a new environment if they are missing.
Update 8/28/2008: I’ve updated the code so that it now optionally exports item level security.