SharePoint has pretty amazing “people” searching capabilities. However, if you are like our organization, your Active Directory data may not be as complete as you’d like it to be. Or maybe you manage identities using another system like PeopleSoft. So the question becomes: How do you get identity information into SharePoint?

I decided to develop a small console application that would insert user profile data, pulled from our PeopleSoft database, into the SharePoint User Profile Store:

What kind of dark magic must be peformed to get information in here!?
What kind of dark magic must be peformed to get information in here!?

Also, we had employee photos, sitting in a web directory on the Central Admin, front-end web server, that I wanted to point to for the profile pictures.

All of this can be done using the SharePoint User Profile Manager class in the SharePoint API.

1. Start a Console Project and add references to System.Web, Microsoft.SharePoint, and Microsoft.Office.Server

(NOTE: If you are deving on a box that doesn’t have WSS or MOSS installed, you won’t be able to debug, however, you can still add the .dll files to your project for compiling.  Just go to your MOSS or WSS server and pull the Microsoft.Office.Server.dll and the Microsoft.SharePoint.dll [%Program Files%Common Files\Microsoft Shared\web server extensions\12\ISAPI] into your project)

Below is the code I used.  Obviously, there are many variants to this to make it work and no two data structures are the same.  However, I think the general concept could work for many different environments.

Essentially, what I did was iterate through a DataTable that had all my employee data in it.  I then pulled up the user profile, using the SharePoint Profile Manager, and inserted the profile property values.

All of the values I’m referencing (PhoneNo, JobTitle, Supervisor_NetworkID, etc.) were available in our PeopleSoft database. If you don’t have access to that level of data, or it’s not being collected in your organization…well…this will be kinda hard.

Finally, I committed the changes in SharePoint and moved on to the next record:

using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace SharePoint_Employee_Photos
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Get usernames
                //Retrieve E-Mail Addresses
                SqlConnection sqlconn1 = new SqlConnection("Data Source=Server;Initial Catalog=Database;User Id=dbuser;Password=dbpassword;");
                SqlCommand sqlcomm1 = new SqlCommand("Stored_Procedure", sqlconn1);
                sqlcomm1.CommandType = CommandType.StoredProcedure;
                SqlDataAdapter sda = new SqlDataAdapter(sqlcomm1);
                DataTable dt = new DataTable();
                sda.Fill(dt);
                using (SPSite spSite = new SPSite(@"http://sharepoint.site.org"))
                {
                    ServerContext siteContext = ServerContext.GetContext(spSite);
                    UserProfileManager pManager = new UserProfileManager(siteContext);

                    foreach (DataRow dr in dt.Rows)
                    {
                        String strUsername = "Domain\\" + dr["NetworkID"].ToString();
                        UserProfile userProfile = null;
                        //Check to see if the profile exists in SharePoint
                        if (pManager.UserExists(strUsername))
                        {
                            userProfile = pManager.GetUserProfile(strUsername);
                            Console.WriteLine("User Success: Domain\\" + dr["NetworkID"].ToString());

                            //Update any of the user profile property values

                            //Photos are made available through a separate SSIS task that queries the PeopleSoft database and outputs
                            //the images to a web folder.  The web folder is served on my Central Admin, web front end server.
                            //Let's make sure the file is there first.
                            if (File.Exists(@"[C:\PhotoWebsite\photos\" + dr["EmpID"].ToString() + ".jpg"))
                            {
                                userProfile[PropertyConstants.PictureUrl].Value = "http://website.photos.org/photos/" + dr["EmpID"].ToString() + ".jpg";
                            }
                            if (!dr["PhoneNo"].Equals(DBNull.Value))
                            {
                                if (!dr["PhoneNo"].Equals(String.Empty))
                                {
                                    userProfile[PropertyConstants.WorkPhone].Value = dr["PhoneNo"].ToString();
                                }
                            }
                            if (!dr["DeptName"].Equals(DBNull.Value))
                            {
                                if (!dr["DeptName"].Equals(String.Empty))
                                {
                                    userProfile[PropertyConstants.Department].Value = dr["DeptName"].ToString();
                                }
                            }
                            if (!dr["JobTitle"].Equals(DBNull.Value))
                            {
                                if (!dr["JobTitle"].Equals(String.Empty))
                                {
                                    userProfile[PropertyConstants.Title].Value = dr["JobTitle"].ToString();
                                }
                            }
                            if (!dr["Supervisor_NetworkID"].Equals(DBNull.Value))
                            {
                                if (!dr["Supervisor_NetworkID"].Equals(String.Empty))
                                {
                                    String strSupervisorUsername = "Domain\\" + dr["Supervisor_NetworkID"].ToString();
                                    if (pManager.UserExists(strSupervisorUsername))
                                    {
                                        userProfile[PropertyConstants.Manager].Value = strSupervisorUsername;
                                        Console.WriteLine("Supervisor Success: Domain\\" + dr["Supervisor_NetworkID"].ToString());
                                    }
                                }
                            }

                            userProfile[PropertyConstants.WorkEmail].Value = dr["Email"].ToString();

                            //Commit the changes
                            userProfile.Commit();
                            Console.WriteLine("Import Success!");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                Console.ReadLine();
            }
        }
    }
}

I found myself in a situation, the other day, where I needed to display items from a Links List on one of my subsites.

The trouble was that the Links List resided on the parent site.  Well, that should be easy right?  Wrong.

I started by using the Content Query Web Part (CQWP).   I selected to “Show items from the following list” and selected the Links list on the parent site.

The list resolved, however, this is what it looked like:

Hmmmm...That dont look right
Hmmmm...That dont look right

It turns out that the CQWP doesn’t know what to do with the URL and Title fields on the Links List.

Also, when you click on the “(Blank)” link, it takes you to the item view of the link and not the page you’re linking to.

So I started Googling and found Ishai Sagi’s clever little tip.

Basically, he exports the web part and makes some modifications.  Essentially, creating a custom web part.

1. I would start by configuring any settings you will want to carry over to your custom web part (Query, Appearance, Title, Sorting, Audience Targeting, etc.)  This will save you from having to make those adjustments after importing the web part to your pages.

2. Click the “edit” button on the web part and select “Export…”

Select "Export..." from the edit menu on the web part
Select "Export..." from the edit menu on the web part

3.  Save the .webpart file to your hard disk.  Then open it using your favorite XML editor.

4.  You’re going to be looking for a property “CommonViewFields”:

<property name="CommonViewFields" type="string" />

Change it to this:

<property name="CommonViewFields" type="string">URL,text</property>

5. Now we need to add a custom “Item Style”, so the web part will understand what to do with the new “CommonViewFields” property. This will require editing the item style XSL of the site.

6. Open up SharePoint Designer and navigate to your site or parent site.

7. Check out and open Style Library > XSL Style Sheets > ItemStyle.xsl

8. We are now looking for the template for the style “NoImage”:

<xsl:template name="NoImage" match="Row[@Style='NoImage']" mode="itemstyle">

9. Make a copy of the complete template:

from

<xsl:template name="NoImage" match="Row[@Style='NoImage']" mode="itemstyle">

to

<xsl:template name="NoImage" match="Row[@Style='NoImage']" mode="itemstyle">

and paste it under the “NoImage” template.

  1. Rename “NoImage” to “LinkList”.
  2. Change the “href” attribute to point to the URL column, the text before the column.
  3. Change the link text to point to the URL column, the text after the column.

10.  Here’s the complete code:

<xsl:template name="LinkList" match="Row[@Style='LinkList']" mode="itemstyle">
 <xsl:variable name="DisplayTitle">
        <xsl:call-template name="OuterTemplate.GetTitle">
            <xsl:with-param name="Title" select="@URL"/>
            <xsl:with-param name="UrlColumnName" select="'URL'"/>
        </xsl:call-template>
    </xsl:variable>
 <xsl:variable name="LinkTarget">
        <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
    </xsl:variable>
 <div id="linkitem" class="item" >
  <div class="bullet link-item">
   <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
   <a>
    <xsl:attribute name="href">
     <xsl:value-of select="substring-before($DisplayTitle,', ')">
     </xsl:value-of>
    </xsl:attribute>
    <xsl:attribute name="title">
     <xsl:value-of select="@Description">
     </xsl:value-of>
    </xsl:attribute>
    <xsl:value-of select="substring-after($DisplayTitle,', ')">
    </xsl:value-of>
   </a>
  </div>
 </div>
</xsl:template>

If you make any mistakes with this part of the styling, it will affect ANY other CQWP you might have deployed on other pages.  Might be a good idea to check on those right now.

11. If everything looks gravy, save the changes to the file and go to the Site Settings of your site or parent site.

12. Under “Galleries”, select “Web Parts”

13. Upload the .webpart file.  Some other settings will come up. Give it a file name, Title, Description. I also like to specify a “Custom” Group value. That way the web part is easy to find in the “Add Web Parts” dialog.

14. Go to your site page or subsite page and Add Web Part.  Add the custom web part to the page.

15. Modify the web part and under Presentation > Styles > Item Style,  select “LinkList” from the dropdown menu:

The links should be showing correctly.  Plus, when you click on them, they go directly to the page you are linking to.

Nice work Ishai!

Even though most organizations deal with Adobe Acrobat and .pdf documents, it doesn’t mean Microsoft added this file type in SharePoint. Sure you can upload .pdf documents to document libraries, but you can forget about crawling those documents and returning results from your search queries.

Thankfully, there are a few resources to address this issue. I will document those resources below, however, here is a condensed list of actions:

1. You have to get your hands on an IFilter from Adobe. Essentially, the IFilter is the link that gets SharePoint to understand what a .pdf document is and how to crawl it. The easiest way to install the IFilter is to download the latest version of Adobe Acrobat Reader on your Central Administration server. The latest versions (8.0 and up) of Reader include the IFilter.

2.  You then need to add the extension to your SharePoint extension list:

  1. Click Start, click Run, type regedit, and then click OK.
  2. Locate and then click the following registry subkey:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0\Search\Applications\GUID\Gather\Search\Extensions\ExtensionList
  3. On the Edit menu, point to New, and then click String Value.
  4. Type 38, and then press ENTER.
  5. Right-click the registry entry that you created, and then click Modify.
  6. In the Value data box, type pdf, and then click OK.

3.  Add the PDF file type to the Extensions List for WSS search by editing the registry:

  1. Start regedit
  2. Open the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0\Search\Applications\{Random GUID}\Gather\Search\Extensions\ExtensionList
  3. Add PDF to the list as a new String Value. Use a new high value e.g. if 37 is the highest value, use “38″ as the key with the value “pdf”

4.  Make a graphic for the .pdf icon to be displayed in the search results and add it to SharePoint files to be referenced:

  1. Create a 16X16 pixel image of the Acrobat file icon.
  2. Save the image as pdf16.gif
  3. Add the Acrobat PDF picture to the SharePoint templates directory. Copy the Acrobat PDF picture called pdf16.gif in the 12 Hive\TEMPLATE\IMAGES folder, e.g. %programfiles%\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\IMAGES.
  4. Bind the Acrobat PDF picture to the PDF file type
  5. Open the 12 Hive\TEMPLATE\XML\DOCICON.XML file
  6. Find the <DocIcons.ByExtension> part
  7. Add the following mapping: <mapping Key=”pdf” Value=”pdf16.gif” OpenControl=”" />

5.  Run IISReset

6. For MOSS 2007 users, Add the file type to Central Administration:

  1. Go to your SSP site
  2. Click on Search Settings > File Types > New File Type
  3. Add pdf as a file type

7. Complete a Full Crawl of your content sources.  This will re-crawl pdf documents that may already be in libraries.

Some of you might see the following warning in your crawl logs:

The file reached the maximum download limit. Check that the full text of the document can be meaningfully crawled.

This is because some of your .pdf files may be too large.  Also, SharePoint wont crawl .pdf documents that have other .pdf documents contained within them.

There doesn’t seem to be a fix for complex .pdf documents, however the size issue can be resolved by adjusting the MaxDownloadSize key in the registry:

  1. Start Registry Editor (Regedit.exe).
  2. Locate the following key in the registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\12.0\Search\Global\Gathering Manager
  3. Open Edit – New – DWORD Value. Name it MaxDownloadSize. Double-click, change the value to Decimal, and type the maximum size (in MB) for files that the gatherer downloads.

You may also want to adjust the timeout period for SharePoint to crawl the documents as you have just adjusted the amount of data that can be crawled and it may take longer:

  1. In Central Administration, on the Application Management tab, in the Search section, click Manage search service.
  2. On the Manage Search Service page, in the Farm-Level Search Settings section, click Farm-level search settings.
  3. In the Timeout Settings section change Connection and Request acknowledgement time.
  1. For WSS3 users: The registry key for is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\
    Web Server Extensions\12.0\Search\Global\Gathering Manager

Default would be MaxDownloadSize (16MB) * MaxGrowFactor (4MB) = 16 * 4 = 64MB of text can be indexed.

After all of your changes, you should restart the CA server and run another full crawl.

Resources:

http://support.microsoft.com/default.aspx/kb/927675

http://blog.tylerholmes.com/2008/04/walkthrough-installing-adobe-v6-pdf.html

http://bloggingabout.net/blogs/harold/archive/2008/10/02/index-pdf-documents-on-sharepoint-using-adobe-pdf-ifilter-9.aspx

http://grounding.co.za/blogs/neil/archive/2008/12/02/working-with-pdf-s-and-sharepoint.aspx

http://fmuntean.wordpress.com/2008/05/22/increase-file-size-crawling/


© 2007 travislowdermilk.com | iKon Wordpress Theme by TextNData | Powered by Wordpress | rakCha web directory