User Profile Privacy Policies

Posted on Posted in SharePoint 2007, STSADM Commands

One of the new features with SharePoint 2007 is the ability to determine who can see different profile properties when looking at a users profile page. This is a great and necessary feature as it makes sure that various privacy concerns are addressed. My company’s privacy policies state that no personal information is to be displayed on our intranet – that includes things such as the birth date and home phone number. By default when we ran the SharePoint upgrade it set some of these sensitive fields to be viewable by everyone.

As part of my upgrade script I needed to make sure that these fields were set appropriately. You can set these values by going to the SSP admin pages and clicking "Profile services policies" located under the "User Profiles and My Sites" section. In order to make these changes in batch during the upgrade I created two commands – the first was just to help me debug and is useful if you wish to get a dump of all the settings: gl-enumprofileprivacypolicies. The second command actually handles the settings of policies (edit only): gl-setprofileprivacypolicy.

In writing the code to handle all this there was one piece that threw me for a loop. You actually have to look in two different places for the policies. Most of the information will be obtained by getting a UserProfileConfigManager object and getting the collection of properties – the privacy policy information is associated with these individual properties which represent the actual profile data properties. The second place to find the data is by getting a collection of PrivacyPolicyItem objects via the PrivacyPolicyManager object. My first thought was that the later should be able to provide me with all the privacy policy information – unfortunately that’s not the case – the later just provides those policies which don’t have a direct profile property associated with them. Both the Property object and the PrivacyPolicyItem object implement the IPrivacyPolicyItem interface which is what enables the information to be stored in multiple locations. The commands I created are detailed below.

1. gl-enumprofileprivacypolicies

This command is really quite simple. It basically has two loops, one for each collection type, and a helper method which converts the objects to XML:

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   5:  InitParameters(keyValues);
   7:  ServerContext serverContext = ServerContext.GetContext(Params["sspname"].Value);
   8:  UserProfileConfigManager manager = new UserProfileConfigManager(serverContext);
   9:  PropertyCollection properties = manager.GetProperties();
  11:  StringBuilder sb = new StringBuilder();
  13:  XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(sb));
  14:  xmlWriter.Formatting = Formatting.Indented;
  16:  xmlWriter.WriteStartElement("PrivacyPolicies");
  17:  xmlWriter.WriteAttributeString("ssp", Params["sspname"].Value);
  19:  foreach (IPrivacyPolicyItem item in properties)
  20:  {
  21:   AddXml(xmlWriter, item);
  22:  }
  24:  PrivacyPolicyManager privacyPolicyManager = ProfileLoader.GetProfileLoader(serverContext).GetUserProfileManager().GetPrivacyPolicy();
  25:  foreach (PrivacyPolicyItem item in privacyPolicyManager.GetAllItems())
  26:  {
  27:   AddXml(xmlWriter, item);
  28:  }
  30:  xmlWriter.WriteEndElement();
  31:  xmlWriter.Flush();
  33:  output += sb.ToString();
  35:  if (Params["outputfile"].UserTypedIn)
  36:  {
  37:   File.WriteAllText(Params["outputfile"].Value, output);
  38:   output = string.Empty;
  39:  }
  41:  return 1;
  42: }
  44: private static void AddXml(XmlTextWriter xmlWriter, IPrivacyPolicyItem item)
  45: {
  46:  xmlWriter.WriteStartElement("Policy");
  48:  xmlWriter.WriteAttributeString("isProperty", (item is Property).ToString());
  50:  if (item is PrivacyPolicyItem)
  51:  {
  52:   xmlWriter.WriteElementString("Id", ((PrivacyPolicyItem)item).Id.ToString());
  53:   xmlWriter.WriteElementString("Group", ((PrivacyPolicyItem)item).Group);
  54:   xmlWriter.WriteElementString("FilterPrivacyItems", ((PrivacyPolicyItem)item).FilterPrivacyItems.ToString());
  55:  }
  56:  else if (item is Property)
  57:  {
  58:   xmlWriter.WriteElementString("Name", ((Property)item).Name);
  59:   xmlWriter.WriteElementString("Description", ((Property)item).Description);
  60:   xmlWriter.WriteElementString("DisplayOrder", ((Property)item).DisplayOrder.ToString());
  61:   xmlWriter.WriteElementString("IsReplicable", ((Property)item).IsReplicable.ToString());
  62:   xmlWriter.WriteElementString("IsSection", ((Property)item).IsSection.ToString());
  63:   xmlWriter.WriteElementString("URI", ((Property)item).URI);
  64:  }
  66:  xmlWriter.WriteElementString("DisplayName", item.DisplayName);
  67:  xmlWriter.WriteElementString("AllowPolicyOverride", item.AllowPolicyOverride.ToString());
  68:  xmlWriter.WriteElementString("DefaultPrivacy", item.DefaultPrivacy.ToString());
  69:  xmlWriter.WriteElementString("PrivacyPolicy", item.PrivacyPolicy.ToString());
  70:  xmlWriter.WriteElementString("UserOverridePrivacy", item.UserOverridePrivacy.ToString());
  72:  xmlWriter.WriteEndElement();
  73: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-enumprofileprivacypolicies

stsadm -o gl-enumprofileprivacypolicies

Lists the user profile privacy policies associated with the SSP.

        -sspname <name of the SSP>
        [-outputfile <file to output results to>]

Here’s an example of how to output all the privacy policy information to a file:

stsadm –o gl-enumprofileprivacypolicies -sspname "SSP1" -outputfile "c:\privacypolicies.xml"

Running the above command will produce results similar to the following (I’ve abbreviated the output for the sake of space):

<PrivacyPolicies ssp="SSP1">  
  <Policy isProperty="True">
    <Description />
    <DisplayName>College Major</DisplayName>
  <Policy isProperty="False">
    <Group>My Links</Group>
    <DisplayName>Links on My Site</DisplayName>

2. gl-setprofileprivacypolicy

This command’s code logic is similar to that of the enum command but includes more logic to handle the different types of changes that can be made. I probably could have cleaned the code up a bit to reduce some of the redundancy but in the end I decided it made more sense to keep the handling of the two object types separate (that and time isn’t something I have a lot of at the moment so I didn’t see the need to spend a lot of time on something that was working).

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   5:  InitParameters(keyValues);
   7:  string name = Params["name"].Value;
   9:  ServerContext serverContext = ServerContext.GetContext(Params["sspname"].Value);
  10:  UserProfileConfigManager manager = new UserProfileConfigManager(serverContext);
  11:  PropertyCollection properties = manager.GetProperties();
  12:  IPrivacyPolicyItem property = properties.GetPropertyByName(name);
  14:  if (property == null)
  15:  {
  16:   // We couldn't find using the system name so try using the display name.
  17:   foreach (IPrivacyPolicyItem item in properties)
  18:   {
  19:    if (item.DisplayName.ToLowerInvariant() == name.ToLowerInvariant())
  20:    {
  21:     if (property != null)
  22:      throw new ArgumentException(string.Format("Duplicate properties found matching the name {0}.  Use the system name instead (use enumprofileprivacypolicies to get system names).", name));
  23:     property = item;
  24:    }
  25:   }
  26:  }
  28:  if (property == null)
  29:  {
  30:   PrivacyPolicyManager privacyPolicyManager = ProfileLoader.GetProfileLoader(serverContext).GetUserProfileManager().GetPrivacyPolicy();
  32:   foreach (PrivacyPolicyItem item in privacyPolicyManager.GetAllItems())
  33:   {
  34:    if (item.DisplayName.ToLowerInvariant() == name.ToLowerInvariant())
  35:    {
  36:     property = item;
  37:     break;
  38:    }
  39:   }
  40:   if (property == null)
  41:    throw new ArgumentException(
  42:     string.Format("Could not find a policy for the User Profile property '{0}'", name));
  45:   if (Params["privacy"].UserTypedIn)
  46:    property.PrivacyPolicy = (PrivacyPolicy)Enum.Parse(typeof(PrivacyPolicy), Params["privacy"].Value, true);
  48:   if (((PrivacyPolicyItem)property).Id != PrivacyPolicyIdConstants.MyColleaguesRecommendations)
  49:   {
  50:    if (Params["defaultprivacy"].UserTypedIn)
  51:     property.DefaultPrivacy = (Privacy)Enum.Parse(typeof(Privacy), Params["defaultprivacy"].Value, true);
  53:    if (Params["allowuseroverride"].UserTypedIn)
  54:     property.UserOverridePrivacy = bool.Parse(Params["allowuseroverride"].Value);
  55:   }
  57:   if (Params["replicable"].UserTypedIn)
  58:    Console.WriteLine("WARNING: Property does not support replication. \"replicable\" parameter ignored.\r\n");
  60:   property.Commit();
  61:  }
  62:  else
  63:  {
  64:   if (Params["privacy"].UserTypedIn)
  65:   {
  66:    if (property.AllowPolicyOverride)
  67:     property.PrivacyPolicy =(PrivacyPolicy) Enum.Parse(typeof (PrivacyPolicy), Params["privacy"].Value, true);
  68:    else 
  69:     Console.WriteLine("WARNING: Property does not allow policy override. \"privacy\" parameter ignored.\r\n");
  70:   }
  72:   if (Params["defaultprivacy"].UserTypedIn)
  73:    property.DefaultPrivacy = (Privacy)Enum.Parse(typeof(Privacy), Params["defaultprivacy"].Value, true);
  75:   if (Params["replicable"].UserTypedIn)
  76:    ((Property)property).IsReplicable = bool.Parse(Params["replicable"].Value);
  78:   if (Params["allowuseroverride"].UserTypedIn)
  79:   {
  80:    if (property.AllowPolicyOverride && !((Property)property).IsReplicable)
  81:     property.UserOverridePrivacy = bool.Parse(Params["allowuseroverride"].Value);
  82:    else
  83:    {
  84:     if (((Property)property).IsReplicable)
  85:      Console.WriteLine("WARNING: Property does not allow policy override because it is marked as Replicable. \"allowuseroverride\" parameter ignored.\r\n");
  86:     else
  87:      Console.WriteLine("WARNING: Property does not allow policy override. \"allowuseroverride\" parameter ignored.\r\n");
  88:    }
  89:   }
  91:   property.Commit();
  92:  }
  93:  return 1;
  94: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-setprofileprivacypolicy

stsadm -o gl-setprofileprivacypolicy

Sets the privacy policy settings for a profile property.

        -sspname <name of the SSP>
        -name <name of the property to edit>
        [-defaultprivacy <public | contacts | organization | manager | private | notset>]
        [-privacy <mandatory | optin | optout | disabled>]
        [-allowuseroverride <true | false>]
        [-replicable <true | false>]

Here’s an example of how to set the privacy policy of the CollegeMajor profile property identified above:

stsadm –o gl-setprofileprivacypolicy -sspname "SSP1" -name "CollegeMajor" -defaultprivacy manager -privacy optin -allowuseroverride true -replicable

One thought on “User Profile Privacy Policies

  1. With regarfds to the replicable option, what is that for? I looked at the technet article for manage policy but it didn’t mention it.

    It appears to me that it is defining what pieces of information from the user profile gets pushed on to the user info tables in SharePoint.

    If that is the case, I am wondering about something set here. There is a user profile property called Account name. It is required and visible to everyone, and the user is not permitted to override it.
    However, it is not marked as replicable.

    We have cases where users change their account names – marriage, divorce, personal choice, etc.

    What we are seeing is that while the rest of their properties are updated in the userinfo table, their account name is not being updated.

    If I manually add the user to a sharepoint group for the site, then the account name is updated.

    Does it make sense that this is not happening automatically because the replicable is not marked?
    Is there a negative side to marking the account property as replicable?

    Thank you

Comments are closed.