Team Foundation Server 2010–Integrate With Existing SharePoint 2010 Farm

A company I was working at went to great lengths to set up a nice SharePoint 2010 farm, complete with high availability, disaster recovery and backups.  This is typical for production environments.  What was interesting is that the development team used TFS and because this was not a software shop, they were the red headed stepchild department with a single VM running TFS with SharePoint Portals and Reporting Services.  When you find yourself in that sort of situation, wouldn’t it be nice to be able to move your Portals to the farm and take advantage of the existing infrastructure and of course the extra goodies that come with running Enterprise?  By being able to take advantage of the enterprise features and of course only having to maintain a single farm environment, it makes a compelling argument to move your SharePoint environments to a single farm and frees up resources on your TFS server (It was only allocated 4 GB or RAM and was always running at about 3.9 GB utilization so was rather slow as well).

So where to start?  Well, SharePoint is probably the next biggest memory/CPU hog behind SQL itself.  SQL Database moves are a little more complex, so for a quick win situation I’m only going to lay out how to migrate your Portals to the SharePoint 2010 farm, as this generally can be done between the development team and the SharePoint admins and don’t need to involve DBAs.

There are a number of features and integration points above and beyond a solution file that requires the install from the TFS media, with the main one being the TFS2010 client API. These allow proper integration with the creation and viewing of Work Items from SharePoint, a new feature with TFS 2010. This works in both SharePoint 2007 and SharePoint 2010 with the level of integration dependent on the version of SharePoint that you are running.

There are three levels of integration with “SharePoint Services 3.0” or “SharePoint Foundation 2010” being the lowest. This level only offers reporting services framed integration for reporting along with Work Item Integration and document management. The highest is SharePoint 2010 Enterprise with Excel Services integration providing some lovely dashboards.

The following are the steps which you need to follow to integrate TFS 2010 with SP 2010

Step 1

The Extensions that you need are on the same installation media as the main TFS install and the only difference is the options you pick during the install.

image

This performs a local deploy of 3 .wsp packages as well as the install, which means a couple things:

  1. It must be installed on every server in the farm
  2. Don’t do this during production hours, unless you have a load balanced environment and can take each server off the LB as you perform the install.
  3. You may need to also perform a reboot

Now that we have the TFS 2010 SharePoint Extensions installed on our SharePoint 2010 farm, we’ll need to configure them both so that they will communicate with each other.

Step:2.a

Once SharePoint extensions installed properly you may need to configure SP 2010 Managed Path for TFS 2010. Every install I’ve seen sets up a managed path so that each TFS Collection can be added as a site collection.  THIS IS NOT NECESSARY!  What I like to do is create a web application with a subweb called “projects” and use that instead of the managed path.  The advantage is that all your portal projects now integrate with the out of the box SharePoint navigation, and you can host multiple TFS collections inside of one “Project Portal”.  This approach also works if you don’t want to break out into separate site collections.

However, the reason for the managed path is that Microsoft wants you to create separate site collections for each TFS collection.  In any case, You will need to add all of the users that will be creating Team Projects to be Administrators of this site so that they will not get an error during the Project Creation Wizard. Later, you may also want to customize this as a proper portal to your projects if you are going to be having lots of them, but it is really just a default placeholder so you have a top level site that you can backup and point at.

However, if you feel the need to use a managed path, now is the time to set one up, so go into Central Admin and choose “Manage Web Applications”

image

Highlight the web application that will host your sharepoint TFS portals and click “Managed Paths”

image

And create a managed path with wildcard inclusion of your choice… When I go this route, same as before I generally use something like “projects” or “tfs”.  I know that some guides say to call it “TFS2010”, but I would recommend against tagging the path with any sort of version number.  Remember once you set this up it may exist for years and survive several upgrades.  You want your users/clients not to have to keep changing URLs every time you upgrade your systems.

 

Step 2.b

If your SharePoint web application authenticates with NTLM instead of kerberos you’ll need to perform this step.  While you’re in Central Admin, go ahead and create an ID in the secure store for “TeamFoundationID” and give it the credentials for your TFS service account.  The reason for this will become clear later when we need to access reporting information.  Kerberos uses a ticketing authentication, NTLM doesn’t, so if we’re trying to access backend data we need to be contentious of not violating the double-hop.  By setting up an ID we can have our Excel services workbooks utilize the ID instead of impersonating for the information.

Step 3

Now that you have set up a home for your project sites, it’s time to let TFS know about it.  Log into your TFS server and open Team Foundation Administration Console

Now you need to configure TFS 2010 connection to SP 2010. In order to have you new TFS 2010 Server talk to and create sites in SharePoint 2010 you need to tell the TFS server where to put them. Navigate to the “SharePoint Web Applications” section. Here you click “Add” and enter the details for the Managed path or site location we just created:

image

 

Step 4

Not done yet… TFS knows where to put the new project portals, but we still need to tell SharePoint that TFS has the permission to create the project sites on the farm.  On your SharePoint 2010 farm, remote into any server and open the Team Foundation Server Administration Console and select the “Extensions for SharePoint Products and Technologies” node. Here we need to “grant access” for our TFS 2010 server to create sites. Click the “Grant access” link and fill out the full URL to the TFS (similar to the Notification URL you see on your tfs server admin console when you select the application tier page)

 

image

Step:5

Once we granted access to the URL now we need to configure the Team Foundation Server 2010 Team Project Collection to create new sites in SharePoint 2010. Click the Edit Default Site Location button. Select our web application “Internal SharePoint 2010 Enterprise Farm” which we have given as “friendly name” in Step 3.  If you are using managed paths instead of a projects parent site, you’ll need to set up a default portal location for each collection that will create a longer url, i.e. “projects/TFS Collection”.  Since most places I’ve worked at don’t use more than one collection, I prefer the parent web approach.  Parent web approach also works with multiple collections wither all pointing to the same default location or broken out into separate URLs.

image

Step 6

Now we’re all set to create new Portal sites in the location we specified.  It is worth noting that it will not create portals for existing Team Projects as this process is run during the Team Project Creation wizard.  Why Microsoft didn’t include the option to create a Portal after the project is created I’ll never know…However, if you really need to create a portal site after the project is created:

  1. You have to create a new temporary project with the create portal option selected and create it in the URL you want for your new portal site for an existing project
  2. Now select the project you want to add a portal to from Team Explorer
  3. Right click the project, select Team Project Settings and select Portal Settings.
  4. Check the Enable team project portal checkbox in the popup window
  5. Then click the Configure URL button. In the popup windows that appears enter the url created at the beginning
  6. Once you’ve pointed to the portal site, you can go back into your TFS admin console and delete the project you used to create the portal site

It’s quite a pain, really hope Microsoft looks at updating this so we can enable a project portal without having to create dummy projects.

You have now integrated SharePoint 2010 and Team Foundation Server 2010!  If you have any existing project portals on your TFS server, now is the time to export/import them to your Enterprise Farm.  After migration I would suggest stopping the “Sharepoint – 80” web application on the TFS server and leaving it off for a couple of weeks before removing it and uninstalling SharePoint from the TFS server.

SharePoint 2010–What Products are Installed on the Farm?

Sometimes when you walk into a new client site, they have what is documented and then they have reality.  Farms get patched, upgraded and various products installed and sometimes there’s no documentation about what actaully exists.  so first thing you want to do is see what you are dealing with.  Here’s some basic commands to see what’s going on.

First, what products are you working with?  Using Powershell we can find out what products are installed on the farm:

(get-spfarm).Products 

This will print out a list of SKU GUID values that you can compare against this list to see what is actually installed on the farm.

  • BEED1F75-C398-4447-AEF1-E66E1F0DF91E: SharePoint Foundation 2010
  • 1328E89E-7EC8-4F7E-809E-7E945796E511: Search Server Express 2010
  • B2C0B444-3914-4ACB-A0B8-7CF50A8F7AA0: SharePoint Server 2010 Standard Trial
  • 3FDFBCC8-B3E4-4482-91FA-122C6432805C: SharePoint Server 2010 Standard
  • 88BED06D-8C6B-4E62-AB01-546D6005FE97: SharePoint Server 2010 Enterprise Trial
  • D5595F62-449B-4061-B0B2-0CBAD410BB51: SharePoint Server 2010 Enterprise
  • BC4C1C97-9013-4033-A0DD-9DC9E6D6C887: Search Server 2010 Trial
  • 08460AA2-A176-442C-BDCA-26928704D80B: Search Server 2010
  • 84902853-59F6-4B20-BC7C-DE4F419FEFAD: Project Server 2010 Trial
  • ED21638F-97FF-4A65-AD9B-6889B93065E2: Project Server 2010
  • 926E4E17-087B-47D1-8BD7-91A394BC6196: Office Web Applications 2010

For example, when I run this on an SPFarm I am currently working on, I get the following results:

image

And that tells me I have SharePoint Foundation 2010, SharePoint Server 2010 Enterprise, and Office Web Applications 2010 installed on the farm.

To figure out what version of SP or CU the SPFarm has been patched to, simply run this command:

(get-spfarm).BuildVersion

And this will output the version of the farm.  Unfortunately I haven’t really been able to find a comprehensive list of build versions, but if you type it into Google the KB article usually comes up in the first couple entries.

SharePoint 2010 Profiles without mySites

Being able to import user profile information from a third party source like Active Directory is usually one of the most critical parts of a functioning Intranet site. What makes this even more powerful is when you layer on the ability for users to edit their own profile information, as well as search for other users. Layer on top of that the social networking features that My Sites provide, and you’ve got killer functionality.

The problem, though, is that some companies want this functionality without actually using My Sites. (This can be for various reasons, usually revolving around governance; an organization might not want employees "wasting time" by posting pictures of their poodle Fluffy, or they might fear that someone will start publishing official content on their private site.)

Well, with SharePoint 2010, this is now possible. You can use the Profile Import Service Application to import user data, and you can allow users to take advantage of People Search and social networking. However, you can do all this while preventing them from being able to actually create My Sites.

To easily accomplish this, go to your User Profile Service Application management page. Under the heading "People", click on the link that says "Manage User Permissions". This will open the following dialog:

clip_image001

For a list of what each of these permissions entails, visit the TechNet article: Enable or disable personal and social features for users or groups (SharePoint Server 2010).

To turn off the ability for all users to create a My Site, create a permission set for "All Authenticated Users", and uncheck the "Create Personal Site" checkbox, then save.

If users could create their own My Site, they would see a link in the My Site header that says "My Content", like this:

clip_image002

However, if a user without a personal site select "My Site" from their user drop down menu, that link will not be available for them:

clip_image003

Users will be able to take advantage of things like editing their profile, tagging content, viewing their org chart, tracking colleagues, etc., but they won’t be able to create their own My Site.

Please note, certain administrative users might still have the ability to create My Sites, even after you’ve disabled Personal sites for users. To completely eliminate the possibility of anyone creating a Personal site, turn off Self Service Site Creation in Central Administration. To do this, open up CA, then navigate to your Web Application. Click on the "Self-Service Site Creation" button on the ribbon, in the "Security" section. This will open up a dialog where you can turn of the ability for users to create a new site in that web application.

clip_image004

Once you turn that off, if a user tried to create their own Personal site, they would get an error saying, "Your personal site cannot be created because Self-Service Site Creation is not enabled. Contact your site administrator for more information."

SharePoint | Add Alternating Row Background Colors to SharePoint Document Libraries with CEWP and JavaScript

SharePoint out of the box has some great tools for displaying documents located in a document library, probably because that’s what a lot of companies use it for.  Out of the box it looks pretty nice, however I had a request that besides having the view display the documents in the document library we also add conditional formatting to allow better visibility to separate the rows with background colors similar to how when we insert a table into a SharePoint page we can apply the a Style like “Table Style 2 – light banded” under Table Tools->Design->Styles to give a banded affect to the Document library, similar to the following:

image

This would allow some of our older colleagues to very clearly follow the rows associated with each item.  Seemed pretty simple and I spent some time trying to find the property that would turn on this feature for the document library.  Turns out there wasn’t one, however with a little creative JavaScript and some quick peeks under the covers at the page source it’s actually very easy to accomplish!

First, open the page you want to apply this style to, and view the source.  Now search for a table element with class="ms-listviewtable" and grab the id value, it should looks something like “onetidDoclibViewTbl0”, but if you’re using certain customized views might look more like “{GUID}-{GUID}”, for the most part though, you won’t need to change this value.

Once you have the ID of the table, you’re going to want to edit the page and insert a Content Editor Web Part.  

image

Now click on it so it brings up the Editing Tools->Format Text tab

image

and under Markup select HTML->Edit HTML Source so it brings up the dialog box.

image

Ok, now we can go ahead and insert our special JavaScript for alternating the row colors of the table, remember to substitute the parameter passed in the getElementByID ( “onetidDoclibViewTbl0”) with the value from your page if different.

<script type="text/javascript">

// Push this to the onload in order to have it run every time page loads
_spBodyOnLoadFunctionNames.push("AlternateRowColorStyle()");

function AlternateRowColorStyle() 
{
    // Set up our variable to identify the table we want alternating colors on.
    // This will usually be one of the tables on the page with class="ms-listviewtable"
    // Replace "onetidDoclibViewTbl0" with the value from your page
    var table = document.getElementById("onetidDoclibViewTbl0"); 

    // We also need to get a collection of rows to apply our styles to
    var RowCollection = table.getElementsByTagName("tr"); 

    //Now we walk through our collection of rows applying our style
    for(RowNumber = 0; RowNumber < RowCollection.length; RowNumber++)
    { 
        if(RowNumber % 2 == 0)
        {
            RowCollection[RowNumber].className = "EvenRow";
        }
        else
        {
            RowCollection[RowNumber].className = "OddRow";
        } 
    }
}
// Once the Rows have been tagged with a class, apply CSS formating
</script>


<style type="text/css">
.OddRow
    {
    BACKGROUND-COLOR: #bee5ff;
    }
.EvenRow
    {
    BACKGROUND-COLOR: white;
    }
</style>

Once you save the page and it reloads, that should trigger the AlternateRowColorStyle() and apply the appropriate classes and CSS to give you a nicely formatted document library view like this:

image

 

And just like that with the CEWP and a little JavaScript we save the day and have a very nicely formatted document library.

SharePoint 2010-Updating User Profile Properties with PowerShell

PowerShell can be a lot of fun and quite powerful because you can script several functions together to create Admin and maintenance function that would take you days to do through the UI.  If I am an admin who has been granted the Manage Profiles right and Full Control in the permissions section of the UPS, I can do some pretty interesting things with a few basic scripts.

For example, imagine that the company has just gone through a massive re-org and now we have a whole bunch of colleagues who have either changed their department or had their department renamed.  Imagine trying to do that for 50 colleagues through the UI, it is doable, but tedious.  Now imagine it was 500 colleagues or even 5000 colleagues.  This is where PowerShell can come in and really save the day.

So, imagine we’re given a Comma Separated Values (CSV) file with the colleague NTID and Department Name and we need to update this information in SharePoint User Profiles.

First step would be to check out the Import-CSV cmdlet ( http://technet.microsoft.com/en-us/library/ee176874.aspx )

Seems like this will work perfectly for our needs, so let’s start building up our script.

I always load in the SharePoint PowerShell snapin:

#First load the SharePoint commands
add-PSSnapIn Microsoft.SharePoint.PowerShell

Now we set up our Job variables, good coding says do this at the top so they are easy to find and change, you can probably further comment them, but the variable names should be descriptive enough so anyone else reading your script will know what’s going on.

#Set up the job variables
$csvfile="Department.csv"
$mySiteUrl = "http://mysite"
$upAttribute = "Department"

We will then need to instantiate

a UserProfileManager object for the mysites, more information about UPM can be found here: http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.userprofilemanager.aspx (Side note: Why hasn’t Microsoft started producing PowerShell Examples in their documentation pages?  You’d think PowerShell is starting to come into its own enough to be listed next to the C# and VB examples)

#Connect to User Profile Manager service
$site = Get-SPSite $mySiteUrl
$context = Get-SPServiceContext $site
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)

Now we transform our CSV file into data we can consume inside our script.

#Create Lists from each item in CSV file
$csvData = Import-Csv $csvfile

And the magic of it all happens here, because we’re going to iterate through our data and apply the new values through our UPM that we’ve instantiated.

#Now iterate through the list to update the attribute with new value
foreach ($line in $csvData)
{
    #Check to see if user profile exists
    if ($profileManager.UserExists($line.NTName))
        {
        #Get user profile and change the value
        $up = $profileManager.GetUserProfile($line.NTName)
        $up[$upAttribute].Value = $line.PropertyVal
        $up.Commit()
        }
    else
    {
        write-host "Profile for user"$line.NTName "cannot be found"
    }
}

Last but definitely not least, release our site object!  Anyone who has dealt with SharePoint programming for more than a day or two will tell you always dispose of your objects when you’re done with them.  Always call dispose on your object even if you think during the course of the run – whether it’s PowerShell or C# – the object will be disposed of anyways.

#Dispose of site object
$site.Dispose()

And there you have it.  A very simple script that will allow us to read in a file containing NTID’s and Departments and update the User Profiles.  Save this script and you’re ready for any re-orgs that come your way!  For those of you who want to cut and past the whole script, here it is all put together:

#First load the SharePoint commands
add-PSSnapIn Microsoft.SharePoint.PowerShell

#Set up the job variables
$csvfile="Department.csv"
$mySiteUrl = "http://mysite"
$upAttribute = "Department"

#Connect to User Profile Manager service
$site = Get-SPSite $mySiteUrl
$context = Get-SPServiceContext $site
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)

#Create Lists from each item in CSV file
$csvData = Import-Csv $csvfile

#Now iterate through the list to update the attribute with new value
foreach ($line in $csvData)
{
    #Check to see if user profile exists
    if ($profileManager.UserExists($line.NTName))
        {
        #Get user profile and change the value
        $up = $profileManager.GetUserProfile($line.NTName)
        $up[$upAttribute].Value = $line.PropertyVal
        $up.Commit()
        }
    else
    {
        write-host "Profile for user"$line.NTName "cannot be found"
    }
}

#Dispose of site object
$site.Dispose()