I recently posted about exporting audiences using my gl-exportaudiences
STSADM command. Of course an export wouldn’t be of much use if you didn’t also have an import so I give you gl-importaudiences
.
Developing this was really easy as I already had code that created an audience and its associated rules. All I had to do was read in the source XML file, do a little refactoring of the audience creation code and then call the rules creation code. One cool thing I added was the ability to output a mapping file which provides the search and replace XML necessary to use my gl-replacefieldvalues
command so that you can replace the old GUIDs used in audience targeting with the new GUID of the new audience. The code can be seen below:
1#if MOSS
2using System;
3using System.Collections;
4using System.Collections.Specialized;
5using System.Collections.Generic;
6using System.IO;
7using System.Text;
8using System.Xml;
9using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
10using Lapointe.SharePoint.STSADM.Commands.SPValidators;
11using Microsoft.Office.Server;
12using Microsoft.Office.Server.Audience;
13
14namespace Lapointe.SharePoint.STSADM.Commands.Audiences
15{
16 public class ImportAudiences : SPOperation
17 {
18 /// <summary>
19 /// Initializes a new instance of the <see cref="ImportAudiences"/> class.
20 /// </summary>
21 public ImportAudiences()
22 {
23 SPParamCollection parameters = new SPParamCollection();
24 parameters.Add(new SPParam("ssp", "ssp", false, null, new SPNonEmptyValidator()));
25 parameters.Add(new SPParam("deleteexisting", "delete"));
26 parameters.Add(new SPParam("inputfile", "input", false, null, new SPFileExistsValidator()));
27 parameters.Add(new SPParam("compile", "c"));
28 parameters.Add(new SPParam("mapfile", "map", false, null, new SPDirectoryExistsAndValidFileNameValidator()));
29
30 StringBuilder sb = new StringBuilder();
31 sb.Append("\r\n\r\nImports all audiences given the provided input file.\r\n\r\nParameters:");
32 sb.Append("\r\n\t-inputfile <file to input results from>");
33 sb.Append("\r\n\t[-deleteexisting <delete existing audiences>]");
34 sb.Append("\r\n\t[-ssp <SSP name>]");
35 sb.Append("\r\n\t[-compile]");
36 sb.Append("\r\n\t[-mapfile <generate a map file to use for search and replace of Audience IDs>]");
37 Init(parameters, sb.ToString());
38 }
39
40 /// <summary>
41 /// Gets the help message.
42 /// </summary>
43 /// <param name="command">The command.</param>
44 /// <returns></returns>
45 public override string GetHelpMessage(string command)
46 {
47 return HelpMessage;
48 }
49
50 /// <summary>
51 /// Executes the specified command.
52 /// </summary>
53 /// <param name="command">The command.</param>
54 /// <param name="keyValues">The key values.</param>
55 /// <param name="output">The output.</param>
56 /// <returns></returns>
57 public override int Execute(string command, StringDictionary keyValues, out string output)
58 {
59 output = string.Empty;
60
61 string inputFile = Params["inputfile"].Value;
62 bool deleteExisting = Params["deleteexisting"].UserTypedIn;
63 bool compile = Params["compile"].UserTypedIn;
64 string mapFile = default(string);
65 if (Params["mapfile"].UserTypedIn)
66 mapFile = Params["mapfile"].Value;
67
68 string xml = File.ReadAllText(inputFile);
69
70 Import(xml, Params["ssp"].Value, deleteExisting, compile, mapFile);
71
72 return OUTPUT_SUCCESS;
73 }
74
75 /// <summary>
76 /// Imports the specified XML.
77 /// </summary>
78 /// <param name="xml">The XML.</param>
79 /// <param name="sspName">Name of the SSP.</param>
80 /// <param name="deleteExisting">if set to <c>true</c> [delete existing].</param>
81 /// <param name="compile">if set to <c>true</c> [compile].</param>
82 /// <param name="mapFile">The map file.</param>
83 private void Import(string xml, string sspName, bool deleteExisting, bool compile, string mapFile)
84 {
85 ServerContext context;
86 if (string.IsNullOrEmpty(sspName))
87 context = ServerContext.Default;
88 else
89 context = ServerContext.GetContext(sspName);
90
91 AudienceManager manager = new AudienceManager(context);
92
93 XmlDocument audiencesDoc = new XmlDocument();
94 audiencesDoc.LoadXml(xml);
95
96 XmlNodeList audienceElements = audiencesDoc.SelectNodes("//Audience");
97 if (audienceElements == null)
98 throw new ArgumentException("The input file does not contain any audience elements.");
99
100 StringBuilder sb = new StringBuilder();
101 XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(sb));
102 xmlWriter.Formatting = Formatting.Indented;
103 xmlWriter.WriteStartElement("Replacements");
104
105 Dictionary<Guid, string> ids = new Dictionary<Guid, string>();
106 if (deleteExisting)
107 {
108 Log("Progrss: Deleting existing audiences.");
109 foreach (Audience au in manager.Audiences)
110 ids.Add(au.AudienceID, au.AudienceName);
111
112 foreach (Guid id in ids.Keys)
113 {
114 if (id == Guid.Empty)
115 continue;
116
117 string name = manager.Audiences[id].AudienceName;
118 manager.Audiences.Remove(id);
119 }
120 }
121
122 foreach (XmlElement audienceElement in audienceElements)
123 {
124 string audienceName = audienceElement.GetAttribute("AudienceName");
125 string audienceDesc = audienceElement.GetAttribute("AudienceDescription");
126
127 Audience audience;
128 bool updatedAudience = false;
129 if (manager.Audiences.AudienceExist(audienceName))
130 {
131 Log("Progress: Updating audience {0}.", audienceName);
132 audience = manager.Audiences[audienceName];
133 audience.AudienceDescription = audienceDesc ?? "";
134 updatedAudience = true;
135 }
136 else
137 {
138 // IMPORTANT: the create method does not do a null check but the methods that load the resultant collection assume not null.
139 Log("Progress: Creating audience {0}.", audienceName);
140 audience = manager.Audiences.Create(audienceName, audienceDesc ?? "");
141 }
142
143 audience.GroupOperation = (AudienceGroupOperation)Enum.Parse(typeof (AudienceGroupOperation),
144 audienceElement.GetAttribute("GroupOperation"));
145
146 audience.OwnerAccountName = audienceElement.GetAttribute("OwnerAccountName");
147
148 audience.Commit();
149
150 if (updatedAudience && audience.AudienceID != Guid.Empty)
151 {
152 // We've updated an existing audience.
153 xmlWriter.WriteStartElement("Replacement");
154 xmlWriter.WriteElementString("SearchString", (new Guid(audienceElement.GetAttribute("AudienceID")).ToString().ToUpper()));
155 xmlWriter.WriteElementString("ReplaceString", string.Format("(?i:{0})", audience.AudienceID.ToString().ToUpper()));
156 xmlWriter.WriteEndElement(); // Replacement
157 }
158 else if (!updatedAudience && audience.AudienceID != Guid.Empty && ids.ContainsValue(audience.AudienceName))
159 {
160 // We've added a new audience which we just previously deleted.
161 xmlWriter.WriteStartElement("Replacement");
162 foreach (Guid id in ids.Keys)
163 {
164 if (ids[id] == audience.AudienceName)
165 {
166 xmlWriter.WriteElementString("SearchString", id.ToString().ToUpper());
167 break;
168 }
169 }
170 xmlWriter.WriteElementString("ReplaceString", string.Format("(?i:{0})", audience.AudienceID.ToString().ToUpper()));
171 xmlWriter.WriteEndElement(); // Replacement
172 }
173
174 XmlElement rulesElement = (XmlElement)audienceElement.SelectSingleNode("rules");
175 if (rulesElement == null | rulesElement.ChildNodes.Count == 0)
176 {
177 audience.AudienceRules = new ArrayList();
178 audience.Commit();
179 continue;
180 }
181
182
183 string rules = rulesElement.OuterXml;
184 Log("Progress: Adding rules to audience {0}.", audienceName);
185 AddAudienceRule.AddRules(sspName, audienceName, rules, true, compile, false, AddAudienceRule.AppendOp.AND);
186 }
187
188 xmlWriter.WriteEndElement(); // Replacements
189
190 if (!string.IsNullOrEmpty(mapFile))
191 {
192 xmlWriter.Flush();
193 File.WriteAllText(mapFile, sb.ToString());
194 }
195 }
196
197 }
198}
199#endif
The help for the command is shown below:
C:\>stsadm -help gl-importaudiences
stsadm -o gl-importaudiences
Imports all audiences given the provided input file.
Parameters:
-inputfile <file to input results from>
[-deleteexisting <delete existing audiences>]
[-ssp <SSP name>]
[-compile]
[-mapfile <generate a map file to use for search and replace of Audience IDs>]
The following table summarizes the command and its various parameters:
Command Name | Availability | Build Date |
---|---|---|
gl-importaudiences | MOSS 2007 | Released: 4/24/2009 |
Parameter Name | Short Form | Required | Description | Example Usage |
---|---|---|---|---|
inputfile | input | Yes | The path to the input file obtained via the gl-exportaudiences command. | -inputfile c:\audiences.xml , -input c:\audiences.xml |
deleteexisting | delete | No | If specified then all existing audiences will be deleted prior to importing the audiences. Note that the “All site users” audience will not be deleted or updated. | -deleteexisting , -delete |
ssp | No | The name of the SSP to import the audiences into. If omitted then the default SSP will be used. | -ssp SSP1 | |
compile | c | No | If specified then compile the audience after creation/update. | -compile , -c |
mapfile | map | No | If specified then an XML file will be generated providing the search and replace strings to use in order to update the GUIDs in your site collections. | -mapfile c:\map.xml , -map c:\map.xml |
The following is an example of how to import all audiences contained in the audiences.xml file:
stsadm -o gl-importaudiences -inputfile c:\audiences.xml -ssp SSP1 -mapfile c:\map.xml -compile
The following shows an example output of the map file after running the above command:
1<Replacements>
2 <Replacement>
3 <SearchString>98E29BEF-8B1E-4113-BB15-6FAF1E6FB8D0</SearchString>
4 <ReplaceString>(?i:1CA1F37E-A50A-4F84-BDCD-8C1279BADB3E)</ReplaceString>
5 </Replacement>
6</Replacements>