Aptillon Blog
22Dec/11

Updating SharePoint 2010 User Information

Posted by Gary Lapointe

One of my clients recently had an issue where a particularly high profile user (CEO) had their title spelled incorrectly in Active Directory; unfortunately the error wasn’t noticed right away and now, despite changing the information in Active Directory, SharePoint was still showing the wrong title in the People Picker when granting the user rights to a Site Collection. Fortunately I had a partial PowerShell script to fix the issue and just needed to only slightly modify it – you can see the original script on pages 299 and 300 of my book. So before I show the modified script it’s first important to understand the problem and why I needed to use a script and why what I had in the book is somewhat incomplete.

Whenever you grant a user rights to a Site Collection or when that user creates/updates/deletes any item within a Site Collection, an entry for the user will be added to a hidden user information list, if not already there. This “User Information List” is located at http://<SiteCollectionUrl>/_catalogs/users/detail.aspx:

SNAGHTMLa064e71

By looking at this list you can see that several key pieces of information are stored here – unfortunately, when you change this information in Active Directory the information stored here is not updated (even after running a full or incremental import via UPS). To complicate matters there is no way to edit the information via the browser, thus the need for a PowerShell script. If you click the user’s name you’ll see the additional properties, including an “Edit Item” option, however, the edit dialog is simply a read-only display of the username, helpful right?:

SNAGHTMLa089b49

So let’s first consider the scenario that my book addresses and assume that a user had had their name and/or email address changed. To accommodate this scenario we simply use the Set-SPUser cmdlet along with the -SyncFromAD parameter. The following script is taken directly from my book and simply iterates through all Site Collections and calls the Set-SPUser cmdlet for the provided user:

function Sync-SPUser([string]$userName) {
  Get-SPSite -Limit All | foreach {
    $web = $_.RootWeb
    if ($_.WebApplication.UseClaimsAuthentication) {
      $claim = New-SPClaimsPrincipal $userName -IdentityType WindowsSamAccountName
      $user = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
    } else {
      $user = $web | Get-SPUser -Identity $userName -ErrorAction SilentlyContinue
    }
    if ($user -ne $null) {
      $web | Set-SPUser -Identity $user -SyncFromAD
    }
    $web.Dispose()
    $_.Dispose()
  }
}

 

Before I make any changes to demonstrate this script and the modifications we’ll make to it, let’s first see how my user is currently set in the Site Collection:

image

And as shown in the People Picker:

SNAGHTMLa14e91b

Note the “Name”/”Display Name”, “Work e-mail”/”E-Mail”, and “Title” fields.

Now I’ll change these values in Active Directory (make the “p” in my last name capitalized, change the title, and set the email) and then run the script (I saved the script as Sync-SPUser.ps1):

SNAGHTMLa17239b

(Note that lowercase “p” is the correct spelling for my name, just in case you were wondering Smile). Now if we look at the user details in the Site Collection and the People Picker we should see the following:

image

SNAGHTMLa1a344d

Notice that the the “Name” / “Display Name” and “Work e-mail” / “E-Mail” fields were updated but not the “Title” field. This is because the Set-SPUser cmdlet and -SyncFromAD parameter only updates these two fields. So how do you update the remaining fields? We simply need to add some code to our function which will grab the SPListItem corresponding to the user from the hidden “User Information List” and then update the corresponding fields manually. The following modified script does this for the “Title” field (note that I’ve changed the function signature to take the title in as a parameter):

function Sync-SPUser([string]$userName, [string]$title) {
  Get-SPSite -Limit All | foreach {
    $web = $_.RootWeb
    if ($_.WebApplication.UseClaimsAuthentication) {
      $claim = New-SPClaimsPrincipal $userName -IdentityType WindowsSamAccountName
      $user = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
    } else {
      $user = $web | Get-SPUser -Identity $userName -ErrorAction SilentlyContinue
    }
    if ($user -ne $null) {
      $web | Set-SPUser -Identity $user -SyncFromAD
      
      $list = $web.Lists["User Information List"]
      $query = New-Object Microsoft.SharePoint.SPQuery
      $query.Query = "<Where><Eq><FieldRef Name='Name' /><Value Type='Text'>$userName</Value></Eq></Where>"
      foreach ($item in $list.GetItems($query)) {
        $item["JobTitle"] = $title
        $item.SystemUpdate()
      }
    }
    $web.Dispose()
    $_.Dispose()
  }
}

The changes to the original function have been highlighted. Note that the internal field name for the “Title” field is “JobTitle” and that is what we are using to set the Title. Now if we run this modified script we should see the Title field updated:

SNAGHTMLa21bc70

SNAGHTMLa236af7

Okay, so what about the other fields (Department, Mobile Number, etc.)? You can see what fields are available to edit by running the following:

SNAGHTMLa265249

In the preceding example I’m grabbing a specific item (in this case the item corresponding to my user) so that I can see the internal field names in context with the data stored by the field – this helps to make sure that I grab the correct field name (i.e., “JobTitle” vs. “Title”). Now you can just add additional fields to update right before the call to SystemUpdate() – simply follow the pattern established for the title field.

So, add this guy to your script library and you’ll be good to go next time someone changes their name, email, or job title.

-Gary

View the original post on Gary’s personal blog for comments and all related downloads: Updating SharePoint 2010 User Information

15Dec/11

SPListItem != SPListItem?

Posted by David Mann

I’m not entirely sure what this means, but I found it curious…

I had a big block of unoptimized code in a project I’m working on and so I lost track of what variables I had and where they had come from.  At one point, I created an SPListItem by retrieving it from an SPListItemCollection.  So  far, so good.  Nothing unusual:

SPListItem itm = lic[0];

Later on, after checking that this item represented an SPFolder, I grabbed it’s corresponding folder object:

SPFolder myFolder = itm.Folder;

Later still, I had to grab a column value.  Forgetting that I had the SPListItem directly, I went this route:

string myValue = (string)myFolder.Item[“myField”];

In stepping through my code, I found that myValue was null, when I knew that it did, in fact, have a value.  Looking at my code to figure out what I could have f-ed up, I saw the itm variable again.  I didn’t expect it would fix my problem, but it would be cleaner to work directly with it instead of going through the folder object, so I changed my code to:

string myValue = (string)itm[“myField”];

Now when stepping through my code, myValue wasn’t null, it threw an ArgumentException error.  WTF?

So, in other words:

SPListItem != SPListItem.Folder.Item

even though both are SPListItems, and I would have assumed the same SPListItem (which they really are because both have the same ID, there’s just something screwy going on with the available fields).

This is mostly a note to myself to fire up Reflector and see what is going on when I have more time.  I’ll try to remember to update this post if I can figure it out.

Imagine that…another head-scratcher from the SharePoint object model…

Smile

Tagged as: ,
To post a comment, view the original posting.
14Dec/11

SharePoint Tips

Posted by David Mann

Last night at the final @TSSSPUG meeting of 2011, Michael Mukalian and I presented an informal couple of sessions covering various tips that we’ve learned over the years of beating our heads against the SharePoint wall.  Here’s a quick review of what I covered…

 

JavaScript & JQuery Intellisense

Add the following lines to the top of your .js files to get intellisense for JQuery and the Client OM:

/// <reference path="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\MicrosoftAjax.js" />
/// <reference path="c:\IntellisenseFiles\jQuery-1.7-vsdoc.js" />
/// <reference path="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\SP.core.debug.js" />
/// <reference path="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\SP.debug.js" />

Note that the path in the second entry is to a folder on my dev machine where I put the –vsdoc files downloaded from the JQuery website.  Adjust your path as appropriate.

Developer Dashboard

I did a quick overview of the DevDash and why it is useful.

CKS:Dev

There’s NO REASON not to use this tool.  Just Do It.  www.cksdev.com

O365 FxCop Rules

If you’re doing Office 365 development, this is another must-have tool: http://o365fxcoprules.codeplex.com/

Resolving Sandbox timeout errors

On a development box only, add the following entry to your HOSTS file to improve the responsiveness of your sandbox process when it is starting up: 127.0.0.1     crl.microsoft.com

Adding a "close" link to the Status Bar with your status messages

var statusId=SP.UI.Status.addStatus("Title", "Hello World Status Message <a href='javascript:SP.UI.Status.removeStatus(statusId)'>[Close]</a>");

Using PowerShell in the VS Pre/Post Deployment steps

%windir%\sysnative\windowspowershell\v1.0\powershell -file "$(ProjectDir)MyPSScriptFile.ps1" where MyPSScriptFIle.ps1 contains your PoSh commands to be run

(source: http://www.thesharepointbaker.co.uk/2011/12/post-deployment-powershell-sharepoint-visual-studio/)

Using LinqPad as a snippet compiler/tester

LinqPad: (free) http://www.linqpad.net/

 

Hopefully folks got some value out of the session.

 

Dave

Tagged as: ,
To post a comment, view the original posting.