views:

1236

answers:

3

We're running SharePoint 2007 SP1 and profiles are imported from Active Directory (a full import runs daily). We had a problem where many of the users were disabled unintentionally in Active Directory and this caused their profiles to be removed from SharePoint. We re-enabled their Active Directory accounts and ran a full import which restored their SharePoint profiles. However, all of their My Links are missing. Is there a method or best practice for restoring them?

A: 

When you do a profile import, you normally risk to loose the existing customization/updated information.

hemalshah
+1  A: 

This post has some pretty good information about MyLinks and its relationship with the SSP database (that's actually where these links are stored counterintuitively.) Hopefully you can have your DBA validate that these links still exist; and that they're associated with the correct profiles.

http://www.k2distillery.com/2009/01/moving-sharepoint-my-links-between-ssps.html

Gurdas Nijor
Thanks for the link, I actually did see that one, but I'm really leary of doing anything directly to the database.
Kwirk
+4  A: 

I posted this because I couldn't find an answer to my problem anywhere. This post by Joel Oleson that describes a similar problem to mine gave me a hint as to where to go looking for the missing data. And This post by Corey Roth showed me how to programatically add the links to a users My Links.

First things first - you need to restore a backup of the database that contains the My Links data. You don't want to restore over your working database, you want to restore it to another location. The links stored in the SSP Database. (You can find out the name of the database by going into Central Admin --> Shared Services Admin then open the menu for the SSP and click on Edit Properties - the SSP Database is listed on the properties page.)

Once the database has been restored you want to retrieve the Link information:

  • the domain account name of the user who owns the link,
  • the url of the link
  • the name of the link

This query will get you that information:

SELECT UPF.NTName, UL.Url, UL.Title
FROM UserLinks UL INNER JOIN UserProfile_full UPF ON UL.recordID = UPF.recordID
INNER JOIN UserPrivacyPolicy UPP ON UL.PolicyId = UPP.id
ORDER BY NTName

(I should note that I did not take into account what group or what privacy level the links were set to, you could probably find that information by looking at the information in the UserPrivacyPolicy table)

I copied the results into Excel & saved it as a .csv file (comma separated list) - just because my production server did not have access to the location where I restored my database. I ordered the columns with Title last because the Title could contain commas and that would mess up how I'm reading in the data. (I checked and the other two fields do not contain commas - you should check yours before making this assumption.)

I then wrote a little console app to import the data. It takes two arguments:

  • the path where the file containing all of the links is located (ie c:\temp\links.csv)
  • the url of the SSP from with the My Links have gone missing (ie https://portal.mydomain.com)

These are the references used:

  • Microsoft.Office.Server (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.Office.Server.dll)
  • Microsoft.SharePoint (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.SharePoint.dll)
  • System
  • System.Data
  • System.Web
  • System.Xml

And this is the code:

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Web;

namespace UserLinks
{
    class Program
    {
        static void Main(string[] args)
        {
            string _accountName = "", _linkTitle = "", _url = "", _tmp = "", _path = "", _SPSsite = "";

            // Check arguments
            if (args.Length != 2)
            {
                ShowUsage();
                return;
            }

            _path = args[0];
            _SPSsite = args[1];

            using (SPSite _site = new SPSite(_SPSsite))
            {
                ServerContext _context = ServerContext.GetContext(_site);
                UserProfileManager _userProfileManger = new UserProfileManager(_context);

                /* Expecting a comma seperated list with 3 columns:  
                 * AccountName in the format Domain\Account name - I am assuming there are no commas in this field
                 * URL - I am assuming there are no commas in this field
                 * Link Title - link title is last because there may be commas in the title
                */
                TextReader _reader = new StreamReader(_path, System.Text.Encoding.Default);
                while (_reader.Peek() != -1)
                {
                    _tmp = _reader.ReadLine();
                    _accountName = _tmp.Substring(0, _tmp.IndexOf(','));
                    _tmp = _tmp.Replace(_accountName + ",", "");
                    _url = _tmp.Substring(0, _tmp.IndexOf(','));
                    _linkTitle = _tmp.Replace(_url + ",", "");

                    try
                    {
                        UserProfile _currentUser = _userProfileManger.GetUserProfile(_accountName);
                        QuickLinkManager _quickLinkManager = _currentUser.QuickLinks;
                        _quickLinkManager.Create(_linkTitle, _url, QuickLinkGroupType.General, null, Privacy.Private);  //I am assuming that all links have no group assigned to them and they are all private links
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(_accountName);
                        Console.WriteLine(ex);
                    }

                }
                _reader.Close();

            }
        }

        private static void ShowUsage()
        {
            Console.WriteLine("Usage");
            Console.WriteLine("UserLinks [FilePath] [SharePoint URL]");
        }

    }
}

So problem solved & as a side benefit, this program can be used to force links to show up in a user's My Links list.

Kwirk
Nice! Thank you for posting such a thorough question / answer.
Alex Angas