A little over a year ago I created one of my first STSADM commands, gl-setpictureurlnewpath, which I developed in order to enable me to set the picture URL property for user profile objects to a new path as the result of the upgrade which resulted in the images going to a new library. This time I needed to do set the property but there was no existing data so the existing command I had wouldn't work as is. I considered reworking the command to accommodate both scenarios but in the end decided to just leave the existing one alone and create a new command which I called gl-setpictureurl.
Updating a user profile object through code is actually really simple - you just get an instance of the UserProfileManager object and then either loop through the items in the collection or use the GetUserProfile method to retrieve a specific UserProfile object. Once you have the object you can edit any of the properties using simple indexer notation (userProfile["PictureURL"].Value = url). Once you've updated the appropriate properties you call the Commit() method on the user profile object.
1: #if MOSS
2: using System;
3: using System.Collections.Specialized;
4: using System.Text;
5: using Lapointe.SharePoint.STSADM.Commands.SPValidators;
6: using Microsoft.Office.Server;
7: using Microsoft.Office.Server.UserProfiles;
8: using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
9: using Microsoft.SharePoint;
10: using System.Net;
11:
12: namespace Lapointe.SharePoint.STSADM.Commands.UserProfiles
13: {
14: public class SetPictureUrl : SPOperation
15: {
16: /// <summary>
17: /// Initializes a new instance of the <see cref="SetPictureUrl"/> class.
18: /// </summary>
19: public SetPictureUrl()
20: {
21: SPParamCollection parameters = new SPParamCollection();
22: parameters.Add(new SPParam("path", "p", true, null, new SPNullOrNonEmptyValidator(), "Please specify the path."));
23: parameters.Add(new SPParam("sspname", "ssp", false, null, new SPNonEmptyValidator(), "Please specify the SSP name."));
24: parameters.Add(new SPParam("username", "u", false, null, new SPNonEmptyValidator(), "Please specify the username."));
25: parameters.Add(new SPParam("overwrite", "ow"));
26: parameters.Add(new SPParam("ignoremissingdata", "ignore"));
27: parameters.Add(new SPParam("validateurl", "validate"));
28:
29: StringBuilder sb = new StringBuilder();
30: sb.Append("\r\n\r\nSets the picture URL path for user profiles. The following variables may be used for dynamic replacement: \"$(username)\", \"$(domain)\", \"$(email)\", \"$(firstname)\", \"$(lastname)\", \"$(employeeid)\".\r\n\r\nParameters:");
31: sb.Append("\r\n\t-path <path to new photo (i.e., \"http://intranet/hr/EmployeePictures/$(username).jpg\") - leave blank to clear>");
32: sb.Append("\r\n\t[-sspname <name of the SSP>]");
33: sb.Append("\r\n\t[-username <DOMAIN\\name>]");
34: sb.Append("\r\n\t[-overwrite]");
35: sb.Append("\r\n\t[-ignoremissingdata]");
36: sb.Append("\r\n\t[-validateurl]");
37:
38: Init(parameters, sb.ToString());
39: }
40: #region ISPStsadmCommand Members
41:
42: /// <summary>
43: /// Gets the help message.
44: /// </summary>
45: /// <param name="command">The command.</param>
46: /// <returns></returns>
47: public override string GetHelpMessage(string command)
48: {
49: return HelpMessage;
50: }
51:
52: /// <summary>
53: /// Runs the specified command.
54: /// </summary>
55: /// <param name="command">The command.</param>
56: /// <param name="keyValues">The key values.</param>
57: /// <param name="output">The output.</param>
58: /// <returns></returns>
59: public override int Execute(string command, StringDictionary keyValues, out string output)
60: {
61: output = string.Empty;
62: Verbose = true;
63:
64: string username = null;
65:
66: if (Params["username"].UserTypedIn)
67: username = Params["username"].Value;
68: string path = Params["path"].Value;
69:
70: ServerContext context = ServerContext.Default;
71: if (Params["sspname"].UserTypedIn)
72: context = ServerContext.GetContext(Params["sspname"].Value);
73:
74: bool overwrite = Params["overwrite"].UserTypedIn;
75: bool ignoreMissingData = Params["ignoremissingdata"].UserTypedIn;
76: bool validateUrl = Params["validateurl"].UserTypedIn;
77:
78: UserProfileManager profManager = new UserProfileManager(context);
79:
80: if (string.IsNullOrEmpty(username))
81: SetPictures(profManager, path, overwrite, ignoreMissingData, validateUrl);
82: else
83: SetPicture(profManager, username, path, overwrite, ignoreMissingData, validateUrl);
84:
85: return OUTPUT_SUCCESS;
86: }
87:
88: #endregion
89:
90: /// <summary>
91: /// Sets the pictures to the specified path for all user profiles.
92: /// </summary>
93: /// <param name="profManager">The prof manager.</param>
94: /// <param name="path">The path.</param>
95: /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
96: /// <param name="ignoreMissingData">if set to <c>true</c> [ignore missing data].</param>
97: /// <param name="validateUrl">if set to <c>true</c> validate the url.</param>
98: public static void SetPictures(UserProfileManager profManager, string path, bool overwrite, bool ignoreMissingData, bool validateUrl)
99: {
100: foreach (UserProfile profile in profManager)
101: {
102: SetPicture(profile, path, overwrite, ignoreMissingData, validateUrl);
103: }
104: }
105:
106: /// <summary>
107: /// Sets the picture URL for the specfied user.
108: /// </summary>
109: /// <param name="profManager">The prof manager.</param>
110: /// <param name="username">The username.</param>
111: /// <param name="path">The path.</param>
112: /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
113: /// <param name="ignoreMissingData">if set to <c>true</c> [ignore missing data].</param>
114: /// <param name="validateUrl">if set to <c>true</c> validate the url.</param>
115: public static void SetPicture(UserProfileManager profManager, string username, string path, bool overwrite, bool ignoreMissingData, bool validateUrl)
116: {
117: if (!string.IsNullOrEmpty(username))
118: {
119: if (!profManager.UserExists(username))
120: {
121: throw new SPException("The username specified cannot be found.");
122: }
123: UserProfile profile = profManager.GetUserProfile(username);
124: SetPicture(profile, path, overwrite, ignoreMissingData, validateUrl);
125: }
126: else
127: throw new ArgumentNullException("username", "The username parameter cannot be null or empty.");
128: }
129:
130: /// <summary>
131: /// Sets the picture.
132: /// </summary>
133: /// <param name="up">Up.</param>
134: /// <param name="path">The path.</param>
135: /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
136: /// <param name="ignoreMissingData">if set to <c>true</c> [ignore missing data].</param>
137: /// <param name="validateUrl">if set to <c>true</c> validate the url.</param>
138: public static void SetPicture(UserProfile up, string path, bool overwrite, bool ignoreMissingData, bool validateUrl)
139: {
140: if (up["PictureURL"].Value != null && !string.IsNullOrEmpty(up["PictureURL"].Value.ToString()) && !overwrite)
141: {
142: Log("\"{0}\" already contains a picture URL. Specify -overwrite to replace existing settings.",
143: up["AccountName"].Value.ToString());
144: return;
145: }
146: if (string.IsNullOrEmpty(path))
147: {
148: path = string.Empty;
149: }
150: else
151: {
152: if (path.Contains("$(username)"))
153: {
154: if (up["UserName"] != null && up["UserName"].Value != null)
155: path = path.Replace("$(username)", up["UserName"].Value.ToString());
156: else
157: {
158: if (up["AccountName"] != null && up["AccountName"].Value != null)
159: path = path.Replace("$(username)", up["AccountName"].Value.ToString().Split('\\')[1]);
160: else
161: {
162: if (!ignoreMissingData)
163: throw new ArgumentException(string.Format("Unable to determine username from existing profile data ({0}).", up.ID));
164: return;
165: }
166: }
167: }
168:
169: if (path.Contains("$(domain)"))
170: {
171: if (up["AccountName"] != null && up["AccountName"].Value != null)
172: path = path.Replace("$(domain)", up["AccountName"].Value.ToString().Split('\\')[0]);
173: else
174: {
175: if (!ignoreMissingData)
176: throw new ArgumentException(string.Format("Unable to determine domain from existing profile data ({0}).", up.ID));
177: return;
178: }
179: }
180:
181: if (path.Contains("$(email)"))
182: {
183: if (up["WorkEmail"] != null && up["WorkEmail"].Value != null)
184: path = path.Replace("$(email)", up["WorkEmail"].Value.ToString());
185: else
186: {
187: if (!ignoreMissingData)
188: throw new ArgumentException(string.Format("Unable to determine email from existing profile data ({0}).", up.ID));
189: return;
190: }
191: }
192:
193: if (path.Contains("$(firstname)"))
194: {
195: if (up["FirstName"] != null && up["FirstName"].Value != null)
196: path = path.Replace("$(firstname)", up["FirstName"].Value.ToString());
197: else
198: {
199: if (!ignoreMissingData)
200: throw new ArgumentException(string.Format("Unable to determine first name from existing profile data ({0}).", up.ID));
201: return;
202: }
203: }
204:
205: if (path.Contains("$(lastname)"))
206: {
207: if (up["LastName"] != null && up["LastName"].Value != null)
208: path = path.Replace("$(lastname)", up["LastName"].Value.ToString());
209: else
210: {
211: if (!ignoreMissingData)
212: throw new ArgumentException(string.Format("Unable to determine lastname from existing profile data ({0}).", up.ID));
213: return;
214: }
215: }
216:
217: if (path.Contains("$(employeeid)"))
218: {
219: if (up["EmployeeID"] != null && up["EmployeeID"].Value != null)
220: {
221: path = path.Replace("$(employeeid)", up["EmployeeID"].Value.ToString());
222: }
223: else
224: {
225: if (!ignoreMissingData)
226: throw new ArgumentException(string.Format("Unable to determine Employee ID from existing profile data ({0}).", up.ID));
227: return;
228: }
229: }
230: }
231:
232: if (validateUrl)
233: {
234: Log("Validating URL \"{0}\" for \"{1}\".", path, up["AccountName"].Value.ToString());
235:
236: //Create a request for the URL.
237: HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path);
238: request.AllowAutoRedirect = false;
239: request.Credentials = CredentialCache.DefaultCredentials;
240: HttpWebResponse serverResponse = (HttpWebResponse)request.GetResponse();
241: if (serverResponse.StatusCode != HttpStatusCode.OK)
242: {
243: Log("Unable to find picture. Setting PictureURL property to empty string.");
244: path = string.Empty;
245: }
246: serverResponse.Close();
247: }
248:
249: Log("Setting picture for \"{0}\" to \"{1}\".", up["AccountName"].Value.ToString(), path);
250:
251: up["PictureURL"].Value = path;
252: up.Commit();
253: }
254:
255: }
256: }
257: #endif
The help for the command is shown below:
C:\>stsadm -help gl-setpictureurl
stsadm -o gl-setpictureurl
Sets the picture URL path for user profiles. The following variables may be used for dynamic replacement: "$(username)"
, "$(domain)", "$(email)", "$(firstname)", "$(lastname)", "$(employeeid)".
Parameters:
-path <path to new photo (i.e., "http://intranet/hr/EmployeePictures/$(username).jpg") - leave blank to clear>
[-sspname <name of the SSP>]
[-username <DOMAIN\name>]
[-overwrite]
[-ignoremissingdata]
[-validateurl]
|
The following table summarizes the command and its various parameters:
| Command Name | Availability | Build Date |
|---|---|---|
| gl-setpictureurl | MOSS 2007 | Released: 9/18/2008
Updated: 4/17/2009 |
| Parameter Name | Short Form | Required | Description | Example Usage |
|---|---|---|---|---|
| path | p | Yes | The path to the images. To substitute dynamic data use the following strings variables within the path: $(username), $(domain), $(email), $(firstname), $(lastname), $(employeeid). The variable names are case sensitive. | -path "http://intranet/hr/EmployeePictures/$(username).jpg"
-p "http://intranet/hr/EmployeePictures/$(username).jpg" |
| sspname | ssp | No | The name of the SSP. If not specified then the default SSP will be used. | -sspname SSP1
-ssp SSP1 |
| username | u | No | The account name associated with the specific user profile to update. If omitted then all user profiles will be updated. | -username "domain\user"
-u "domain\user" |
| overwrite | ow | No | If provided then existing data values will be overwritten. If omitted then any profile objects with existing data will be ignored. | -overwrite
-ow |
| ignoremissingdata | ignore | No | If specified then do not error if a specified variable value cannot be found. Note that if the value is not found then the property value will not be set. | -ignoremissingdata
-ignore |
| validateurl | validate | No | If specified then perform a web request to see if the resultant URL is valid. If the result is not valid then the property value will be set to an empty string. | -validaturl
-validate |
The following is an example of how to set the picture URL property of all user profiles:
stsadm -o gl-setpictureurl -path "http://intranet/hr/EmployeePictures/$(username).jpg" -overwrite
Updated 4/17/2009: The command has been updated to include the employeeid variable as well as the ignoremissingdata and the validateurl parameters. Thanks to Tim Griepp for providing some code that I used to motivate myself to look at this command again :)


