If you saw my last post, Exporting List Security Settings, then you know what this post is all about. I needed a way to be able to copy the security settings from one variation to another or from one farm to another. I already had my gl-copylistsecurity
command which could handle the first piece of this but I needed another set of commands to handle going from one farm to another. The first was gl-exportlistsecurity
which handles the exporting – the second command is, obviously enough, gl-importlistsecurity
.
Like the export code this was fairly easy for me to do because I already had the code for the copy command – it was just a matter of refactoring it so that the source could be an XML file rather than another list:
1/// <summary>
2/// Imports the security.
3/// </summary>
4/// <param name="inputFile">The input file.</param>
5/// <param name="url">The URL.</param>
6/// <param name="includeItemSecurity">if set to <c>true</c> [include item security].</param>
7public static void ImportSecurity(string inputFile, string url, bool includeItemSecurity)
8{
9 using (SPSite site = new SPSite(url))
10 using (SPWeb web = site.OpenWeb())
11 {
12 XmlDocument xmlDoc = new XmlDocument();
13 xmlDoc.Load(inputFile);
14
15 Log("Start Time: {0}.", DateTime.Now.ToString());
16
17 foreach (XmlElement listElement in xmlDoc.SelectNodes("//List"))
18 {
19 SPList list = null;
20
21 try
22 {
23 list = web.GetList(web.ServerRelativeUrl.TrimEnd('/') + "/" + listElement.GetAttribute("Url"));
24 }
25 catch (ArgumentException) { }
26 catch (FileNotFoundException) { }
27
28 if (list == null)
29 {
30 Console.WriteLine("WARNING: List was not found - skipping.");
31 continue;
32 }
33
34 ImportSecurity(list, web, includeItemSecurity, listElement);
35
36 }
37 Log("Finish Time: {0}.\r\n", DateTime.Now.ToString());
38 }
39}
40
41/// <summary>
42/// Imports the security.
43/// </summary>
44/// <param name="targetList">The target list.</param>
45/// <param name="web">The web.</param>
46/// <param name="includeItemSecurity">if set to <c>true</c> [include item security].</param>
47/// <param name="listElement">The list element.</param>
48internal static void ImportSecurity(SPList targetList, SPWeb web, bool includeItemSecurity, XmlElement listElement)
49{
50 Log("Progress: Processing list \"{0}\".", targetList.RootFolder.ServerRelativeUrl);
51
52 try
53 {
54 int writeSecurity = int.Parse(listElement.GetAttribute("WriteSecurity"));
55 int readSecurity = int.Parse(listElement.GetAttribute("ReadSecurity"));
56
57 if (writeSecurity != targetList.WriteSecurity)
58 targetList.WriteSecurity = writeSecurity;
59
60 if (readSecurity != targetList.ReadSecurity)
61 targetList.ReadSecurity = readSecurity;
62
63 // Set the security on the list itself.
64 SetObjectSecurity(web, targetList, targetList.RootFolder.ServerRelativeUrl, listElement);
65
66 // Set the security on any folders in the list.
67 SetFolderSecurity(web, targetList, listElement);
68
69 // Set the security on any items in the list.
70 if (includeItemSecurity)
71 SetItemSecurity(web, targetList, listElement);
72
73 targetList.Update();
74
75 }
76 finally
77 {
78 Log("Progress: Finished processing list \"{0}\".", targetList.RootFolder.ServerRelativeUrl);
79 }
80}
81
82/// <summary>
83/// Sets the folder security.
84/// </summary>
85/// <param name="web">The web.</param>
86/// <param name="list">The list.</param>
87/// <param name="listElement">The list element.</param>
88private static void SetFolderSecurity(SPWeb web, SPList list, XmlElement listElement)
89{
90 foreach (XmlElement folderElement in listElement.SelectNodes("Folder"))
91 {
92 string folderUrl = folderElement.GetAttribute("Url");
93 SPListItem folder = null;
94 foreach (SPListItem tempFolder in list.Folders)
95 {
96 if (tempFolder.Folder.Url.ToLowerInvariant() == folderUrl.ToLowerInvariant())
97 {
98 folder = tempFolder;
99 break;
100 }
101 }
102 if (folder == null)
103 {
104 Log("Progress: Unable to locate folder '{0}'.", EventLogEntryType.Warning, folderUrl);
105 continue;
106 }
107 SetObjectSecurity(web, folder, folderUrl, folderElement);
108 }
109}
110
111/// <summary>
112/// Sets the item security.
113/// </summary>
114/// <param name="web">The web.</param>
115/// <param name="list">The list.</param>
116/// <param name="listElement">The list element.</param>
117private static void SetItemSecurity(SPWeb web, SPList list, XmlElement listElement)
118{
119 foreach (XmlElement itemElement in listElement.SelectNodes("Item"))
120 {
121 int itemId = int.Parse(itemElement.GetAttribute("Id"));
122 SPListItem item = null;
123 try
124 {
125 item = list.GetItemById(itemId);
126 }
127 catch (ArgumentException)
128 {
129 // no-op
130 }
131 if (item == null)
132 {
133 Log("Progress: Unable to locate item '{0}'.", EventLogEntryType.Warning, itemId.ToString());
134 continue;
135 }
136 SetObjectSecurity(web, item, "Item " + itemId, itemElement);
137 }
138}
139
140/// <summary>
141/// Sets the object security.
142/// </summary>
143/// <param name="web">The web.</param>
144/// <param name="targetObject">The target object.</param>
145/// <param name="itemName">Name of the item.</param>
146/// <param name="sourceElement">The source element.</param>
147private static void SetObjectSecurity(SPWeb web, ISecurableObject targetObject, string itemName, XmlElement sourceElement)
148{
149
150 bool hasUniqueRoleAssignments = bool.Parse(sourceElement.GetAttribute("HasUniqueRoleAssignments"));
151
152 if (!hasUniqueRoleAssignments && targetObject.HasUniqueRoleAssignments)
153 {
154 Log("Progress: Setting target object to inherit permissions from parent for \"{0}\".", itemName);
155 targetObject.ResetRoleInheritance();
156 return;
157 }
158 else if (hasUniqueRoleAssignments && !targetObject.HasUniqueRoleAssignments)
159 {
160 Log("Progress: Breaking target object inheritance from parent for \"{0}\".", itemName);
161 targetObject.BreakRoleInheritance(false);
162 }
163 else if (!hasUniqueRoleAssignments && !targetObject.HasUniqueRoleAssignments)
164 {
165 Log("Progress: Ignoring \"{0}\". Target object and source object both inherit from parent.", itemName);
166 return; // Both are inheriting so don't change.
167 }
168 if (hasUniqueRoleAssignments && targetObject.HasUniqueRoleAssignments)
169 {
170 while (targetObject.RoleAssignments.Count > 0)
171 targetObject.RoleAssignments.Remove(0); // Clear out any existing permissions
172 }
173
174 foreach (XmlElement roleAssignmentElement in sourceElement.SelectNodes("RoleAssignments/RoleAssignment"))
175 {
176 string memberName = roleAssignmentElement.GetAttribute("Member");
177 SPRoleAssignment existingRoleAssignment = GetRoleAssignement(web, targetObject, memberName);
178
179 if (existingRoleAssignment != null)
180 {
181 if (AddRoleDefinitions(web, existingRoleAssignment, roleAssignmentElement))
182 {
183 existingRoleAssignment.Update();
184
185 Log("Progress: Updated \"{0}\" at target object \"{1}\".", memberName, itemName);
186 }
187 }
188 else
189 {
190 SPPrincipal principal = GetPrincipal(web, memberName);
191 if (principal == null)
192 {
193 Log("Progress: Unable to add Role Assignment for \"{0}\" - Member \"{1}\" not found.", EventLogEntryType.Warning, itemName, memberName);
194 continue;
195 }
196
197 SPRoleAssignment newRA = new SPRoleAssignment(principal);
198 AddRoleDefinitions(web, newRA, roleAssignmentElement);
199
200 if (newRA.RoleDefinitionBindings.Count == 0)
201 {
202 Log("Progress: Unable to add \"{0}\" to target object \"{1}\" (principals with only \"Limited Access\" cannot be added).", EventLogEntryType.Warning, memberName, itemName);
203 continue;
204 }
205
206 Log("Progress: Adding new Role Assignment \"{0}\".", newRA.Member.Name);
207
208 targetObject.RoleAssignments.Add(newRA);
209
210 existingRoleAssignment = GetRoleAssignement(targetObject, principal);
211 if (existingRoleAssignment == null)
212 {
213 Log("Progress: Unable to add \"{0}\" to target object \"{1}\".", EventLogEntryType.Warning, memberName, itemName);
214 }
215 else
216 {
217 Log("Progress: Added \"{0}\" to target object \"{1}\".", memberName, itemName);
218 }
219 }
220 }
221}
222
223/// <summary>
224/// Adds the role definitions.
225/// </summary>
226/// <param name="web">The web.</param>
227/// <param name="roleAssignment">The role assignment.</param>
228/// <param name="roleAssignmentElement">The role assignment element.</param>
229/// <returns></returns>
230private static bool AddRoleDefinitions(SPWeb web, SPRoleAssignment roleAssignment, XmlElement roleAssignmentElement)
231{
232 bool modified = false;
233 foreach (XmlElement roleDefinitionElement in roleAssignmentElement.SelectNodes("RoleDefinitionBindings/RoleDefinition"))
234 {
235 string name = roleDefinitionElement.GetAttribute("Name");
236 if (name == "Limited Access")
237 continue;
238
239 SPRoleDefinition existingRoleDef = web.RoleDefinitions[name];
240 if (existingRoleDef == null)
241 {
242 Log("Progress: Adding new Role Definition \"{0}\".", name);
243
244 SPBasePermissions perms = SPBasePermissions.EmptyMask;
245 foreach (string perm in roleDefinitionElement.GetAttribute("BasePermissions").Split(','))
246 {
247 perms = perms | (SPBasePermissions)Enum.Parse(typeof(SPBasePermissions), perm, true);
248 }
249 existingRoleDef = new SPRoleDefinition();
250 existingRoleDef.Name = name;
251 existingRoleDef.BasePermissions = perms;
252 existingRoleDef.Description = roleDefinitionElement.GetAttribute("Description");
253 existingRoleDef.Order = int.Parse(roleDefinitionElement.GetAttribute("Description"));
254 existingRoleDef.Update();
255
256 SPWeb tempWeb = web;
257 while (!tempWeb.HasUniqueRoleDefinitions)
258 tempWeb = tempWeb.ParentWeb;
259
260 tempWeb.RoleDefinitions.Add(existingRoleDef);
261 }
262 if (!roleAssignment.RoleDefinitionBindings.Contains(existingRoleDef))
263 {
264 roleAssignment.RoleDefinitionBindings.Add(existingRoleDef);
265 modified = true;
266 }
267 }
268 List<SPRoleDefinition> roleDefsToRemove = new List<SPRoleDefinition>();
269 foreach (SPRoleDefinition roleDef in roleAssignment.RoleDefinitionBindings)
270 {
271 if (roleDef.Name == "Limited Access")
272 continue;
273
274 bool found = false;
275 foreach (XmlElement roleDefinitionElement in roleAssignmentElement.SelectNodes("RoleDefinitionBindings/RoleDefinition"))
276 {
277 if (roleDef.Name == roleDefinitionElement.GetAttribute("Name"))
278 {
279 found = true;
280 break;
281 }
282 }
283 if (!found)
284 {
285 roleDefsToRemove.Add(roleDef);
286 modified = true;
287 }
288 }
289 foreach (SPRoleDefinition roleDef in roleDefsToRemove)
290 {
291 Log("Progress: Removing '{0}' from '{1}'", roleDef.Name, roleAssignment.Member.Name);
292 roleAssignment.RoleDefinitionBindings.Remove(roleDef);
293 }
294 return modified;
295}
296
297/// <summary>
298/// Gets the role assignement.
299/// </summary>
300/// <param name="web">The web.</param>
301/// <param name="securableObject">The securable object.</param>
302/// <param name="memberName">Name of the member.</param>
303/// <returns></returns>
304private static SPRoleAssignment GetRoleAssignement(SPWeb web, ISecurableObject securableObject, string memberName)
305{
306 SPPrincipal principal = GetPrincipal(web, memberName);
307 return GetRoleAssignement(securableObject, principal);
308}
309
310/// <summary>
311/// Gets the role assignement.
312/// </summary>
313/// <param name="securableObject">The securable object.</param>
314/// <param name="principal">The principal.</param>
315/// <returns></returns>
316private static SPRoleAssignment GetRoleAssignement(ISecurableObject securableObject, SPPrincipal principal)
317{
318 SPRoleAssignment ra = null;
319 try
320 {
321 ra = securableObject.RoleAssignments.GetAssignmentByPrincipal(principal);
322 }
323 catch (ArgumentException)
324 { }
325 return ra;
326}
327
328/// <summary>
329/// Gets the principal.
330/// </summary>
331/// <param name="web">The web.</param>
332/// <param name="memberName">Name of the member.</param>
333/// <returns></returns>
334private static SPPrincipal GetPrincipal(SPWeb web, string memberName)
335{
336 foreach (SPPrincipal p in web.SiteUsers)
337 {
338 if (p.Name == memberName)
339 return p;
340 }
341 foreach (SPPrincipal p in web.SiteGroups)
342 {
343 if (p.Name == memberName)
344 return p;
345 }
346 return null;
347}
This command simply takes in the output from the gl-exportlistsecurity
command so naturally anything that command doesn’t support this one won’t either. The syntax can be seen below:
C:\>stsadm -help gl-importlistsecurity
stsadm -o gl-importlistsecurity
Imports security settings using data output from gl-exportlistsecurity.
Parameters:
-url <url to import security to>
-inputfile <file to import settings from>
[-quiet]
[-includeitemsecurity]
The following table summarizes the command and its various parameters:
Command Name | Availability | Build Date |
---|---|---|
gl-importlistsecurity | WSS v3, MOSS 2007 | Released: 4/12/2008, Updated: 8/28/2008 |
Parameter Name | Short Form | Required | Description | Example Usage |
---|---|---|---|---|
url | Yes | The web URL to import the security settings to. | -url http://portal | |
inputfile | file | Yes | The file with the security information to import. | -inputfile "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 imported. | -includeitemsecurity , -items |
Here’s an example of how to import the security settings:
stsadm -o gl-importlistsecurity -url http://portal/documents/forms/allitems.aspx -inputfile c:\security.xml
Update 8/28/2008: I’ve updated the code so that it now supports importing item level security.