In an effort to wrap up my audience related STSADM commands I created a command that allows me to set the audience compilation schedule via STSADM. I had to do some disassembling to figure out how to do this and it turned out that the code was virtually identical to what I had done for the gl-setuserprofileimportschedule
command. So it turned out that I was able to create this command by simply coping the code from my other command and then just tweaking a couple lines to load up different class types. I named the command gl-setaudiencecompilationschedule
. The downside of this code (and the code it’s based off of) is that I had to use reflection to get it done as all the classes are marked internally (no idea why). If anyone knows of a way to do this without all the reflect I’m all ears.
Here’s the code – it’s ugly, but it works:
1#if MOSS
2using System;
3using System.Collections.Specialized;
4using System.Reflection;
5using System.Text;
6using System.Threading;
7using Lapointe.SharePoint.STSADM.Commands.SPValidators;
8using Microsoft.Office.Server;
9using Microsoft.Office.Server.UserProfiles;
10using Microsoft.SharePoint;
11using Microsoft.SharePoint.Administration;
12using Microsoft.SharePoint.StsAdmin;
13using PropertyInfo=System.Reflection.PropertyInfo;
14using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
15
16namespace Lapointe.SharePoint.STSADM.Commands.TimerJob
17{
18 public class SetAudienceCompilationSchedule : SPOperation
19 {
20 private enum OccurrenceType
21 {
22 daily,
23 weekly,
24 monthly
25 }
26
27 /// <summary>
28 /// Initializes a new instance of the <see cref="SetAudienceCompilationSchedule"/> class.
29 /// </summary>
30 public SetAudienceCompilationSchedule()
31 {
32 SPParamCollection parameters = new SPParamCollection();
33 parameters.Add(new SPParam("sspname", "ssp", false, null, new SPNonEmptyValidator(), "Please specify the SSP name."));
34 parameters.Add(new SPParam("occurrence", "oc", true, null, new SPRegexValidator("^daily$|^weekly$|^monthly$")));
35 parameters.Add(new SPParam("hour", "hour", true, null, new SPIntRangeValidator(0, 23)));
36 parameters.Add(new SPParam("day", "day", false, null, new SPIntRangeValidator(1, 31)));
37 string regex = "^" + string.Join("$|^", Enum.GetNames(typeof (DayOfWeek))) + "$";
38 parameters.Add(new SPParam("dayofweek", "dayofweek", false, null, new SPRegexValidator(regex.ToLowerInvariant() + "|" + regex)));
39 parameters.Add(new SPParam("enabled", "enabled", false, "true", new SPTrueFalseValidator()));
40 parameters.Add(new SPParam("runjob", "run"));
41
42 StringBuilder sb = new StringBuilder();
43 sb.Append("\r\n\r\nSets the audience compilation schedule.\r\n\r\nParameters:");
44 sb.Append("\r\n\t[-sspname <SSP name>]");
45 sb.Append("\r\n\t-occurrence <daily|weekly|monthly>");
46 sb.Append("\r\n\t-hour <hour to run (0-23)>");
47 sb.Append("\r\n\t[-day <the day to run if monthly is specified>]");
48 sb.AppendFormat("\r\n\t[-dayofweek <the day of week to run if weekly is specified ({0})>]", string.Join("|", Enum.GetNames(typeof(DayOfWeek))).ToLowerInvariant());
49 sb.Append("\r\n\t[-enabled <true|false> (default is true)]");
50 sb.Append("\r\n\t[-runjob]");
51 Init(parameters, sb.ToString());
52 }
53
54 #region ISPStsadmCommand Members
55
56 /// <summary>
57 /// Gets the help message.
58 /// </summary>
59 /// <param name="command">The command.</param>
60 /// <returns></returns>
61 public override string GetHelpMessage(string command)
62 {
63 return HelpMessage;
64 }
65
66 /// <summary>
67 /// Runs the specified command.
68 /// </summary>
69 /// <param name="command">The command.</param>
70 /// <param name="keyValues">The key values.</param>
71 /// <param name="output">The output.</param>
72 /// <returns></returns>
73 public override int Execute(string command, StringDictionary keyValues, out string output)
74 {
75 output = string.Empty;
76
77
78
79 #region Check Arguments
80
81 OccurrenceType occurrence = (OccurrenceType)Enum.Parse(typeof(OccurrenceType), Params["occurrence"].Value, true);
82 if (occurrence == OccurrenceType.monthly && !Params["day"].UserTypedIn)
83 {
84 output = "Please specify the day to run the import.";
85 output += GetHelpMessage(command);
86 return (int)ErrorCodes.SyntaxError;
87 }
88 if (occurrence == OccurrenceType.weekly && !Params["dayofweek"].UserTypedIn)
89 {
90 output = "Please specify the day of week to run the import.";
91 output += GetHelpMessage(command);
92 return (int)ErrorCodes.SyntaxError;
93 }
94
95 #endregion
96
97 string day = Params["day"].Value;
98 string dayofweek = Params["dayofweek"].Value;
99 string sspname = Params["sspname"].Value;
100 int hour = int.Parse(Params["hour"].Value);
101 bool enabled = bool.Parse(Params["enabled"].Value);
102 bool runJob = Params["runjob"].UserTypedIn;
103 if (!enabled && runJob)
104 throw new SPSyntaxException("The runjob parameter cannot be specified when enabled is set to false.");
105
106 ServerContext current;
107 if (Params["sspname"].UserTypedIn)
108 current = ServerContext.GetContext(sspname);
109 else
110 current = ServerContext.Default;
111
112 // What follows is a whole lot of reflection which is required in order to get the SPScheduledJob object.
113 // Problem is that the only way to get the correct instance of this object is to use several internal
114 // classes, methods, and properties - why on earth these were not made public is absolutely beyond me!
115
116 // The bulk of the reflection is recreating the following which was taken from
117 // Microsoft.SharePoint.Portal.UserProfiles.AdminUI.Sched.InitializeComponent().
118 // Once we have the job objects we can start setting properties.
119 /*
120 private void InitializeComponent()
121 {
122 ServerContext current = ServerContext.Current;
123 UserProfileApplication userProfileApplication = current.UserProfileApplication;
124 try
125 {
126 using (PortalApplication.BeginSecurityContext())
127 {
128 JobSchedulerSharedApplicationCollection applications = new JobSchedulerSharedApplicationCollection(SPFarm.Local.Services.GetValue<JobSchedulerService>(string.Empty));
129 JobSchedulerSharedApplication sharedApplication = (JobSchedulerSharedApplication) applications[current.SharedResourceProvider];
130 ScheduledJobCollection jobs = new ScheduledJobCollection(sharedApplication);
131 this.AudienceCompileScheduler.Job = jobs[userProfileApplication.AudienceCompilationJobId];
132 }
133 }
134 catch (Exception)
135 {
136 throw;
137 }
138 }
139 */
140
141 // UserProfileApplication userProfileApplication = current.UserProfileApplication;
142 object userProfileApplication = Utilities.GetPropertyValue(current, "UserProfileApplication");
143
144 // The SSP is locked down so we need to use reflection to get at it.
145 object sharedResourceProvider = Utilities.GetSharedResourceProvider(current);
146
147 // JobSchedulerService jobSchedulerService = SPFarm.Local.Services.GetValue(typeof(JobSchedulerService));
148 Type jobSchedulerServiceType = Type.GetType("Microsoft.Office.Server.Administration.JobSchedulerService, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
149
150
151 MethodInfo getValue =
152 SPFarm.Local.Services.GetType().GetMethod("GetValue",
153 BindingFlags.NonPublic | BindingFlags.Public |
154 BindingFlags.Instance | BindingFlags.InvokeMethod, null, new Type[] {typeof(Type), typeof(string)}, null);
155
156 object jobSchedulerService = getValue.Invoke(SPFarm.Local.Services,
157 new object[]
158 {
159 jobSchedulerServiceType, string.Empty
160 });
161
162
163 // JobSchedulerSharedApplicationCollection application = new JobSchedulerSharedApplicationCollection(jobSchedulerServiceType);
164 Type jobSchedulerSharedApplicationCollectionType = Type.GetType("Microsoft.Office.Server.Administration.JobSchedulerSharedApplicationCollection, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
165
166 ConstructorInfo jobSchedulerSharedApplicationCollectionConstructor =
167 jobSchedulerSharedApplicationCollectionType.GetConstructor(
168 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
169 null,
170 new Type[] {jobSchedulerService.GetType()}, null);
171 object applications = jobSchedulerSharedApplicationCollectionConstructor.Invoke(new object[] { jobSchedulerService });
172
173 // JobSchedulerSharedApplication jobSchedulerSharedApplication = applications[sharedResourceProvider];
174 PropertyInfo itemProp = applications.GetType().GetProperty("Item",
175 BindingFlags.NonPublic |
176 BindingFlags.Instance |
177 BindingFlags.InvokeMethod |
178 BindingFlags.GetProperty |
179 BindingFlags.Public);
180 object jobSchedulerSharedApplication = itemProp.GetValue(applications, new object[] { sharedResourceProvider });
181
182
183 //ScheduledJobCollection scheduledJobCollection = new ScheduledJobCollection(sharedApplication);
184 Type scheduledJobCollectionType = Type.GetType("Microsoft.Office.Server.Administration.ScheduledJobCollection, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
185 ConstructorInfo scheduledJobCollectionConstructor =
186 scheduledJobCollectionType.GetConstructor(
187 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
188 null,
189 new Type[] {jobSchedulerSharedApplication.GetType()}, null);
190 object scheduledJobCollection = scheduledJobCollectionConstructor.Invoke(new object[] { jobSchedulerSharedApplication });
191
192
193 // userProfileApplication.AudienceCompilationJobId
194 Guid audienceCompilationJobId = (Guid)Utilities.GetPropertyValue(userProfileApplication, "AudienceCompilationJobId");
195
196
197
198 // ScheduledJob compilationJob = scheduledJobCollection[audienceCompilationJobId];
199 itemProp = scheduledJobCollection.GetType().GetProperty("Item",
200 BindingFlags.NonPublic |
201 BindingFlags.Instance |
202 BindingFlags.InvokeMethod |
203 BindingFlags.GetProperty |
204 BindingFlags.Public);
205 object compilationJob = itemProp.GetValue(scheduledJobCollection, new object[] { audienceCompilationJobId });
206
207
208 PropertyInfo scheduleProp = compilationJob.GetType().GetProperty("Schedule",
209 BindingFlags.FlattenHierarchy |
210 BindingFlags.NonPublic |
211 BindingFlags.Instance |
212 BindingFlags.InvokeMethod |
213 BindingFlags.GetProperty |
214 BindingFlags.Public);
215
216 MethodInfo update =
217 compilationJob.GetType().GetMethod("Update",
218 BindingFlags.NonPublic |
219 BindingFlags.Public |
220 BindingFlags.Instance |
221 BindingFlags.InvokeMethod |
222 BindingFlags.FlattenHierarchy,
223 null,
224 new Type[] {typeof (bool)}, null);
225
226 // Woohoo!!! We are finally at a point where we can actually set the schedule - what a pain the @$$ that was!!!
227 SPSchedule schedule;
228
229 if (occurrence == OccurrenceType.daily)
230 {
231 schedule = SetUserProfileImportSchedule.ScheduledJobHelper.GetScheduleDaily(hour);
232 }
233 else if (occurrence == OccurrenceType.weekly)
234 {
235 schedule = SetUserProfileImportSchedule.ScheduledJobHelper.GetScheduleWeekly((DayOfWeek)Enum.Parse(typeof(DayOfWeek), dayofweek, true), hour);
236 }
237 else if (occurrence == OccurrenceType.monthly)
238 {
239 schedule = SetUserProfileImportSchedule.ScheduledJobHelper.GetScheduleMonthly(int.Parse(day), hour);
240 }
241 else
242 throw new Exception("Unknown occurance type.");
243
244 Type scheduledJobType = Type.GetType("Microsoft.Office.Server.Administration.ScheduledJob, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
245
246
247 // fullImportJob.Schedule = schedule;
248 scheduleProp.SetValue(compilationJob, schedule, null);
249
250 // fullImportJob.Enabled = enabled;
251 Utilities.SetPropertyValue(compilationJob, scheduledJobType, "Disabled", !enabled);
252
253 // fullImportJob.Update(true);
254 update.Invoke(compilationJob, new object[] { true });
255
256 if (runJob)
257 {
258 // fullImportJob.Execute();
259 Utilities.ExecuteMethod(compilationJob, "Execute", new Type[] { }, new object[] { });
260 }
261
262 if (runJob)
263 {
264 // We want to wait until the import is finished before moving on in case we are being run in a batch that requires this to complete before continueing.
265 UserProfileConfigManager manager = new UserProfileConfigManager(current);
266 while (manager.IsImportInProgress())
267 Thread.Sleep(500);
268 }
269
270
271 return OUTPUT_SUCCESS;
272 }
273
274 #endregion
275
276 }
277}
278#endif
The help for the command is shown below:
C:\>stsadm -help gl-setaudiencecompilationschedule
stsadm -o gl-setaudiencecompilationschedule
Sets the audience compilation schedule.
Parameters:
[-sspname <SSP name>]
-occurrence <daily|weekly|monthly>
-hour <hour to run (0-23)>
[-day <the day to run if monthly is specified>]
[-dayofweek <the day of week to run if weekly is specified (sunday|monday|tuesday|wednesday|thursday|friday|saturday)>]
[-enabled <true|false> (default is true)]
[-runjob]
The following table summarizes the command and its various parameters:
Command Name | Availability | Build Date |
---|---|---|
gl-setaudiencecompilationschedule | MOSS 2007 | Release: 8/14/2008 |
Parameter Name | Short Form | Required | Description | Example Usage |
---|---|---|---|---|
sspname | ssp | No | The name of the SSP that the audiences to compile are associated with. If omitted the default SSP will be used. | -sspname SSP1 , -ssp SSP1 |
occurrence | oc | Yes | Specifies how frequently the compilation should occur. Valid values are “daily”, “weekly”, and “monthly”. | -occurrence daily , -oc monthly |
hour | Yes | The hour in which to run the compilation. This should be an integer between 0 and 23 (where 0 is 12:00am and 23 is 11:00pm). | -hour 22 | |
day | No, unless occurrence is monthly | The day of the month to run the compilation job. Valid values are between 1 and 31. | -day 1 | |
dayofweek | No, unless occurrence is weekly | The day of the week to run the compilation job. Valid values are “sunday”, “monday”, “tuesday”, “wednesday”, “thursday”, and “saturday”. | -dayofweek saturday | |
enabled | No | “true” to enable the compilation schedule, “false” to disable it. If not specified then the compilation schedule will be enabled. | -enabled true | |
runjob | run | No | If specified then the compilation job will be immediately executed after setting the schedule. | -runjob , -run |
The following is an example of how to set the compilation schedule to run every Satruday at 10:00pm:
stsadm -o gl-setaudiencecompilationschedule -occurrence weekly -hour 22 -dayofweek saturday -enabled true -runjob