If you don’t have SharePoint configured at the time that you upgrade your Team Foundation Server or when you attach a new TPC, then one of the things that you might be left with is this:
- The Team Project is working fine
- The SharePoint site is working fine
- But they’re not linked or associated with each other as a Project Portal
Unfortunately (until now) the only way to link these two together again is to use Visual Studio to open up the Project Portal Settings for each team project and tick the box. If you have do to this for more than a few team projects on a server, it’s pretty tedious. 5 is about the limit of my patience, but I have seen customers do up to 100.
EnableProjectPortal.exe
Download EnableProjectPortal.zip
Usage
EnableProjectPortal.exe <tfs server url> <team project id> <sharepoint relative path> <owned web identifier>
Example
EnableProjectPortal.exe http://localhost:8080/tfs/" "2eb9c8a2-2243-4897-ac88-602bef270dd5" "/sites/TailspinToysCollection/Tailspin Toys" "224C16E0-00DA-4C98-9042-3D21228B2511"
This console application will use the ICatalogService API to do the equivalent of the '[x] Enable team project portal' checkbox. You will need to collect some information before you can use it, but at least you can build up a batch file and do lots of team projects at once.
Get a list of projects and their IDs
There's plenty of different ways to get a list of Team Projects and their GUIDs, but this one is fine for a once off:
1. Open SQL Server Management Studio
2. Connect to Team Project Collection database (e.g. Tfs_DefaultCollection)
3. Run the following query:
SELECT project_name, project_id
FROM tbl_Projects
WHERE [state] = 'WellFormed'
ORDER BY project_name
It should return something like this:
project_name | project_id |
Tailspin Toys | 2EB9C8A2-2243-4897-AC88-602BEF270DD5 |
Copy and paste this list into Excel
Get a list of the SharePoint sites and their WebIdentifier IDs
Once again, there's more than one way to get this information other than going directly to the database. But for a once off like this, it will be fine:
1. Open SQL Server Management Studio
2. Connect to the SharePoint content database that holds your team sites (e.g. WSS_Content)
3. Run the following query:
SELECT
FullUrl as 'RelativePath',
Id as 'OwnedWebIdentifier'
FROM AllWebs
ORDER BY RelativePath
It should return something like this:
RelativePath | OwnedWebIdentifier |
B032339F-D997-4B2C-B5D0-3CB6064D2F1A | |
sites/FabrikamFiberCollection | 919B7437-B8D9-4B56-8AB5-D5B22605278F |
sites/FabrikamFiberCollection/FabrikamFiber | 7485DD68-2C1D-4089-AD1E-7FA43D92065D |
sites/team | 1E3082E4-6517-401A-8D5F-22DF8ED1B308 |
Paste this into somewhere else in your Excel workbook
Construct a mapping table
Now we need to map the team projects/team project IDs to sharepoint sites. Use Excel to construct a table with the following format:
project_name | project_id | RelativePath | OwnedWebIdentifier |
Tailspin Toys | 2EB9C8A2-2243-4897-AC88-602BEF270DD5 | sites/TailspinToysCollection/Tailspin Toys | 7FC7E412-F49C-488B-A023-8C1D61AE34C7 |
FabrikamFiber | FD6FA263-B3F9-45E3-96AF-AD67E75C9FF7 | sites/FabrikamFiberCollection/FabrikamFiber | 7485DD68-2C1D-4089-AD1E-7FA43D92065D |
Now we can use this table construct the arguments for EnableProjectPortals.exe. You can use this formula in a new column to the right, in Excel:
=CONCATENATE("EnableProjectPortal.exe ""http://localhost:8080/tfs/"" """,B2,""" """,C2,""" """,D2,"""")
Repairing connections
Once all the portal settings have been established, you should open the Team Foundation Server Administration Console and choose “Repair Connections”.
This will make sure all the SharePoint permissions and properties are set correctly.
At this point you are done and you have saved yourself or your customer a lot of tedious clicking.
The Code
All the thanks go to Phil (another Aussie expat on the TFS team) for this utility. I was just the beneficiary and now I'm the messenger.
Here's the guts of it where we set up a dependency property in the ICatalogService between the team project and the SharePoint site.
var projectPortalNodes = teamProject.NodeReferences[0].QueryChildren(new Guid[] { CatalogResourceTypes.ProjectPortal }, true, CatalogQueryOptions.ExpandDependencies);
CatalogNode projectPortalNode = null;
if (projectPortalNodes.Count > 0)
{
// It already exists, so lets overwrite/set with the values we want.
projectPortalNode = projectPortalNodes[0];
}
else
{
// It doesn't exist, so lets create it.
projectPortalNode = teamProject.NodeReferences[0].CreateChild(CatalogResourceTypes.ProjectPortal, "Project Portal");
}// Set properties
projectPortalNode.Resource.Properties["ResourceSubType"] = "WssSite";
projectPortalNode.Resource.Properties["RelativePath"] = sharePointRelativePath;
projectPortalNode.Resource.Properties["OwnedWebIdentifier"] = sharePointOwnedWebIdentifier;// BUG: Use the first sharepoint web resource. Doesn't work with multiple.
projectPortalNode.Dependencies.SetSingletonDependency("ReferencedResource", sharepointWebAppResources[0].NodeReferences[0]);catalogService.SaveNode(projectPortalNode);