February 2008 - Posts
Configure TFS to use RSA clearTrust
Objectives
- Learn key remote access scenarios and when to apply them.
- Provide remote access to your Microsoft® Visual Studio® 2005 Team Foundation Server (TFS) over the Internet.
- Improve remote access performance by using the Team Foundation Server Proxy.
Overview
This chapter explains how to provide remote access to TFS over the Internet.
You can choose from one of the following three options in order to provide remote access:
- You can provide access to TFS over a virtual private network (VPN).
- You can provide access to TFS through a reverse proxy such as Microsoft Internet Security and Acceleration (ISA) Server.
- You can host your TFS server on an extranet.
Versions of TFS prior to Service Pack 1 (SP1) support only VPN access. TFS SP1 adds support for Basic authentication. This enables the extranet and reverse proxy solutions as well as VPN.
How to Use This Chapter Use this chapter to set up your TFS server for remote access over the Internet.
To gain the greatest benefits from this chapter, you should:
- Use the scenarios list. Consult the scenarios list to determine quickly which approach you should adopt to provide external Internet access to your server.
- Use the referenced walkthroughs. Use the walkthroughs in this chapter for step-by-step guidance on installing and configuring the certificates and Secure Sockets Layer (SSL) access to be used with Basic and Digest authentication.
- Use the “Improving Remote Access Performance” section. Read the “Improving Remote Access Performance” section** to identify ways to reduce the amount of traffic that needs to be sent over the Internet.
Key Strategies
The following are solution strategies for providing remote access to a TFS server:
- Use a VPN connection. Your TFS sits inside the internal network, and external users access it over a VPN. Internal users access a TFS directly.
- Publish your TFS through a reverse proxy. Your TFS sits inside the internal network, and one or more reverse proxy machines, such as ISA Server, bring in client requests from the Internet to your TFS.
- Locate your TFS in the extranet (“hosted scenario”). Only external clients access your TFS, and it is located outside of the firewall on an extranet.
Common Scenarios
- Remote office. If you are supporting remote users with VPN access, use the VPN solution. This is the easiest solution to enable, provides well-understood security, allows remote access to all TFS features, and allows you to use the TFS Proxy to improve performance.
- Offshore team. If you are supporting remote users without VPN access or without access to the domain, use the reverse proxy scenario. This solution is more difficult to set up, but it enables remote users to access an internally located TFS without the need for VPN.
- Hosted community. If you are supporting a set of remote users who will be using a TFS installation dedicated to their use, such as a community development site, use the extranet scenario. This solution gives you the most separation between the remote users and your internal network resources.
Using a VPN connection
With this approach, your remote development team uses a direct VPN connection to your TFS on your internal network. If you have TFS without SP1, or if you require Integrated Windows authentication, then using a VPN connection is your only option. TFS is designed to work in low-bandwidth situations, such as VPN access, and provides acceptable performance when used in this scenario.
Advantages
- All TFS features work, including the TFS Proxy.
- This approach supports the use of Integrated Windows authentication and enables you to leverage existing enterprise infrastructure.
- If you already have a VPN set up, this is the easiest solution to adopt.
Disadvantages
- A VPN solution might not be set up for your infrastructure, or might not be available to your remote users.
For more information about creating a VPN, see
http://support.microsoft.com/kb/324747.
Publishing TFS Through a Reverse Proxy
With this approach, you install a TFS server on your internal network and use the ISA Server Web publishing functionality to expose it to the external network. Remote users access TFS over SSL and use Basic authentication. This option will not work unless you have TFS SP1 installed.
Networks without a domain controller on the perimeter
If you do not have a domain controller on your perimeter network, you can open a port on the firewall to allow a Lightweight Directory Access Protocol (LDAP) connection from the ISA Server to your internal domain controller, specifically to authenticate external TFS users.
Networks with a domain controller on the perimeter
If you do have a domain controller on your perimeter network, remote users can authenticate directly against the perimeter domain controller. One-way trust between the internal and perimeter domain controllers allows external users to access the TFS server. Internal users access the TFS server directly, using Integrated Windows authentication.
Advantages
- Reverse proxies, such as ISA Server, authenticate users and inspect traffic.
- Your remote users do not need access to the domain.
- Your remote users do not need VPN access.
Disadvantages
- You cannot use the TFS Proxy at the remote location.
- Your remote users cannot add users to TFS groups.
- Your remote users cannot add Microsoft Active Directory® groups to folders in source control.
- Your remote users will not be able to initiate or manage builds remotely.
- Your remote users cannot create new team projects.
- Your remote users cannot publish test results to your TFS.
Note: Whenever you use Basic authentication, use SSL. Basic authentication transmits credentials in clear text. Use SSL to protect this information.
Locating TFS in an Extranet (“Hosted Scenario”)
With this approach, you install your complete TFS infrastructure?both application tier and data tier?inside your perimeter network, off of your internal intranet. All connections to your TFS come over the Internet, whether they are from external or internal users. TFS can work with or without a domain controller (DC). If your perimeter network does not have access to a DC, the Active Directory service features of TFS will not work. For example, adding users to TFS groups, or adding an Active Directory group to folders in source control, will not work without a DC. This option will not work unless you have TFS SP1 installed.
Advantages
- Your TFS users are cleanly segregated from your internal network.
- Your remote users do not need access to the domain.
Disadvantages
- You cannot use the TFS Proxy at the remote location.
- Your remote users cannot initiate or manage builds.
- Your remote users cannot create new team projects.
- Your remote users cannot publish test results to the TFS.
- Internal users must connect to the extranet TFS over SSL just like external users.
Note: Whenever you use Basic authentication, use SSL. Basic authentication transmits credentials in clear text. Use SSL to protect this information.
Basic Authentication / SSL
If you are using TFS SP1 and want to support the extranet or reverse proxy scenario, you need to enable Basic authentication over SSL by configuring IIS on your TFS application tier. With Basic authentication, logon credentials are passed over the Internet using an unprotected Base64 encoded format. To protect your client’s credentials, use only Basic authentication over a Secure HTTP (HTTPS) connection that uses SSL.
Use an Internet Server API (ISAPI) filter so that remote clients connect using Basic authentication over SSL, while local clients still connect using Integrated Windows authentication. The ISAPI filter looks for clients that you have configured as “external/Internet” and strips out NTLM authentication on the 401 response to force these clients to use other authentication methods, such as Basic authentication.
More information
- For more information about how to configure your TFS server to require Basic authentication and HTTPS over remote connections, see “Walkthrough: Setting up Team Foundation Server to Require HTTPS and Secure Sockets Layer (SSL)” at http://msdn2.microsoft.com/en-us/library/aa833873(VS.80).aspx
- For more information about setting up the ISAPI filter, see “Walkthrough: Setting up Team Foundation Server with Secure Sockets Layer (SSL) and an ISAPI Filter” at http://msdn2.microsoft.com/en-us/library/aa833872(VS.80).aspx
- For more information about ISAPI filters for TFS, see James Manning’s blog post “The TFS extranet ISAPI filter mechanics” at http://blogs.msdn.com/jmanning/archive/2006/10/27/the-tfs-quot-extranet-quot-isapi-filter-mechanics.aspx
Team Foundation Server Proxy
The TFS Proxy is not required to enable remote access but is an optional cache for source control files. To help improve the performance that your remote team experiences, you can install a TFS Proxy in remote offices that connect to your TFS through a VPN. This improves performance by caching source control files on the remote office’s proxy server. Whenever the remote client needs access to source code in the source control repository, it will request the source from the TFS Proxy. The proxy will then return a local version from its cache if it is available. If the source is not in the cache, the proxy will request the source from the remote TFS server. This reduces network traffic and improves source control responsiveness at the remote location.
Tips to improve proxy performance
Consider the following recommendations for improving proxy performance:
- Ensure that caching is enabled, and monitor the performance of your cache. Monitor the performance counters (installed by default) and event logs (for errors and warnings) on your proxy server regularly, to see how your proxy is performing. Note that the TFS Proxy saves cache performance statistics to an Extensible Markup Language (XML) file named ProxyStatistics.xml, and that you can change the interval for saving these statistics. The ProxyStatistics.xml file is located in the App_Data folder in the proxy installation directory.
- Run a scheduled task regularly to retrieve the latest files to the proxy server. This helps to ensure that the latest versions of the files are available in the proxy cache, and that subsequent client requests for these files result in a cache hit.
- If you know that large files are going to be downloaded over a low-bandwidth (< 3 megabits per second Mbps) network, set the executionTimeout configuration to an appropriate value in Web.config. The default value is one hour <httpRuntime executionTimeout="3600"/>.
- If the proxy is going to be down for an extended time, disable the proxy on the clients to prevent fruitless reconnections. By default, reconnections are attempted every five minutes.
- Consider using workspace cloaking to hide specific workspaces from being viewed and to prevent unnecessary file transfers. Cloaking hides specified workspace folders from view, increases performance bandwidth, and conserves local disk space by preventing folders and files that you do not currently need from being copied to your local workspace. Although you can cloak an existing folder mapping in your workspace, a better approach is to create a new folder mapping that is specifically intended to be cloaked.
For more information about these performance optimization guidelines, see “Distributed / Remote Development” in “Guidelines: Source Control Guidelines” in this guide.
Mirrored Accounts
The TFS Proxy is supported in remote offices only over a VPN connection. However, if you have deployed your TFS using the extranet or reverse proxy scenario for a small remote team that requires the TFS Proxy, you can use mirrored accounts to enable the proxy.
To enable the proxy, you can use workgroup accounts with matching usernames and passwords on the TFS, the TFS Proxy, and each of the remote client computers. The fact that you need to maintain the exact username/password match for all users in three different locations increases administration time and restricts this workaround to small remote teams.
More information*
Remote Build Server
To improve remote team performance further, you can set up a build server in the remote office. If you have a TFS Proxy installed in the remote office, it will act like any other source control client and get code from the proxy before each build. A remote build server has the following advantages:
- Team builds from the remote team impact that team’s build server, rather than increasing load on the internal build server.
- Remote builds provide binaries to the remote team, without the need to transmit the binaries over the network.
Don’t use the remote build server as a complete replacement for builds generated on the internal build server. Even if the remote build is generated from the same source code version as the internal build, you might see different behavior because of build or source configuration differences between the servers. As a guideline, base important testing on the internal build, especially when you’re nearing a release.
Note: The application tier communicates with the build server on port 9191. If you have a remote build server, set up your firewall so that the application tier can connect on this port.
Python for .Net
Python for .NET is available as a source release and as a Windows installer for various versions of Python and the common language runtime from the Python for .NET.
Here is a small tutorial for getting started:
Importing Modules
from System import String
from System.Collections import *
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import Form
Using Classes
from System.Drawing import Point
p = Point(5, 5)
Using Generics
from System.Collections.Generic import Dictionary
from System import *
dict1 = Dictionary[String, String]()
dict2 = Dictionary[String, Int32]()
dict3 = Dictionary[String, Type]()
Fields And Properties
from System import Environment
name = Environment.MachineName
Environment.ExitCode = 1
Using Indexers
from System.Collections import Hashtable
table = Hashtable()
table["key 1"] = "value 1"
Using Methods
from System import Environment
drives = Environment.GetLogicalDrives()
Overloaded and Generic Methods
from System import Console
Console.WriteLine.__overloads__[bool](true)
Console.WriteLine.__overloads__[str]("true")
Console.WriteLine.__overloads__[int](42)
Delegates And Events
def my_handler(source, args):
print 'my_handler called!'
# instantiate a delegate
d = AssemblyLoadEventHandler(my_handler)
# use it as an event handler
AppDomain.CurrentDomain.AssemblyLoad += d
Exception Handling
from System import NullReferenceException
try:
raise NullReferenceException("aiieee!")
except NullReferenceException, e:
print e.Message
print e.Source
Using Arrays
from System import Array
myarray = Array[int](10)
Using Collections
domain = System.AppDomain.CurrentDomain
for item in domain.GetAssemblies():
name = item.GetName()
Type Conversion
items = System.Array.CreateInstance(Point, 3)
for i in range(3):
items[i] = Point(0, 0)
items[0].X = 1 # won't work!!
Enjoy
Cookie Collection and CookieContainer
When using System.Net or Web Services, you might want to receive or send cookies, perhaps for session state maintenance or in some rare situations for proxy authentication.
The first thing we are tempted to do is to access WebResponse.Cookies collection.
But then it returns no cookies. Why?
It turns out that unless you assign a CookieContainer to the WebRequest, you won't be able to get the WebResponse.Cookies.
It is not very intuitive. Why would I need to create a cookie container to get cookies?
Notice that you need to create a cookie container but then you get cookie collection from WebResponse.
Here is some sample code
CookieContainer CC = new CookieContainer();
HttpWebRequest Req = (HttpWebRequest) WebRequest.Create("http://localhost/CookieTest/first.aspx");
Req.Proxy = null;
Req.UseDefaultCredentials = true;
//YOU MUST ASSIGN A COOKIE CONTAINER FOR THE REQUEST TO PULL THE COOKIES
Req.CookieContainer = CC;
Res = (HttpWebResponse)Req.GetResponse();
//DUMP THE COOKIES
Console.WriteLine("----- COOKIES -----");
if(Res.Cookies != null && Res.Cookies.Count != 0)
{
foreach(Cookie c in Res.Cookies)
{
Console.WriteLine("\t" + c.ToString());
}
}
else
{
Console.WriteLine("No Cookies");
|}
OK fine you might say - but what is the difference between CookieCollection and a CookieContainer?
They kind of look the same.
The difference is that the CookieCollection is the cookies obtained for the SPECIFIC request.
CookieContainer is designed to be a store of all the cookies for one more requests.
To that extent, the CookieContainer is designed to be a hashtable of "domain - CookieCollection" pairs.
What this means is that for the next requests you create, you can safely assign the cookiecontainer from the previous request.
But then you might be wondering whether we send the cookies that we are not supposed to. Fear not.
The CookieContainer is designed to be safe.
When the second request is sent the we look at the URI and the path you are using and send only those cookies that we can safely send as per the RFC.
Here is the complete sample for Cookies
using System;
using System.Threading;
using System.Net;
using System.Text;
using System.IO;
public class Test
{
public static void Main(string[] args)
{
Stream s = null;
StreamReader sr = null;
HttpWebResponse Res = null;
CookieContainer CC = new CookieContainer();
try
{
//----------------------------------------------------
//FIRST REQUEST
//----------------------------------------------------
HttpWebRequest Req = (HttpWebRequest) WebRequest.Create("http://localhost/CookieTest/first.aspx");
Req.Proxy = null;
Req.UseDefaultCredentials = true;
//YOU MUST ASSIGN A COOKIE CONTAINER FOR THE REQUEST TO PULL THE COOKIES
Req.CookieContainer = CC;
Res = (HttpWebResponse)Req.GetResponse();
//DUMP THE COOKIES
Console.WriteLine("----- COOKIES -----");
if(Res.Cookies != null && Res.Cookies.Count != 0)
{
foreach(Cookie c in Res.Cookies)
{
Console.WriteLine("\t" + c.ToString());
}
}
else
{
Console.WriteLine("No Cookies present");
}
s = Res.GetResponseStream();
sr = new StreamReader(s, Encoding.ASCII);
Console.WriteLine("----- RESPONSE -----");
Console.WriteLine("\t" + sr.ReadToEnd());
//----------------------------------------------------
//SECOND REQUEST
//----------------------------------------------------
Req = (HttpWebRequest) WebRequest.Create("http://localhost/CookieTest/second.aspx");
Req.Proxy = null;
Req.UseDefaultCredentials = true;
//TO TRANSFER COOKIES TO THE NEXT PAGE
Req.CookieContainer = CC;
Res = (HttpWebResponse)Req.GetResponse();
//DUMP THE COOKIES
Console.WriteLine("----- COOKIES -----");
if(Res.Cookies != null && Res.Cookies.Count != 0)
{
foreach(Cookie c in Res.Cookies)
{
Console.WriteLine("\t" + c.ToString());
}
}
else
{
Console.WriteLine("No Cookies present");
}
s = Res.GetResponseStream();
sr = new StreamReader(s, Encoding.ASCII);
Console.WriteLine("----- RESPONSE -----");
Console.WriteLine("\t" + sr.ReadToEnd());
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
finally
{
if(sr != null) sr.Close();
if(s != null) s.Close();
}
}
}
Get List of Workspaces from TFS Server
Here is three ways to do this,
- Using the "Workspaces Command".
- Download Workspace Sidekick for UI option.
- Our you can write it using Team System API:
private void GetWorkspace()
{
TeamFoundationServer server = ServerConnection.ConnectTfs(*TFS Name*);
VersionControlServer vcs = (VersionControlServer)server.GetService(typeof(VersionControlServer));
Workspace[] wss = GetWorkspaces();
foreach (Workspace ws in wss)
{
//ws.Name.ToString();
}
}
public Workspace[] GetWorkspaces()
{
try
{
return vcs.QueryWorkspaces(null, vcs.AuthenticatedUser, System.Net.Dns.GetHostName().ToString());
}
catch
{
throw;
}
}
Hope I helped.
Python
Yesterday is was participate in the "Third Blogger's Convention" in Microsoft Israel and I realized that I can write about anything beside cakes, cats etc… :-)
So I want to talk about a Script Language that I love.
Maybe you heard about this language or maybe not, but there is a very powerful scripts language called Python.
So What is Python?
Python Programming Language is a dynamic object-oriented programming language that can be used for many kinds of software development.
It offers strong support for integration with other languages and tools, comes with extensive standard libraries, and can be learned in a few days.
Many Python programmers report substantial productivity gains and feel the language encourages the development of higher quality, more maintainable code.
Demonstration:
I made the following script for a coworker that want to download 1000 pictures form a web site, you can go and download all those pictures manually one by one
and as you know this may take some time or write a script in Python.
So here is the Python Script in 3 Lines toke me approximately 1.5 minutes to write:
import urllib
[urllib.urlretrieve(x,"d:\\shai\\" + os.path.basename(x)) for x in ['http://www.shvoong.co.il/shvoong/2022/%03d.jpg ' % x for x in xrange(0,1000)]]
Hope you've enjoy this post and I'll bring more examples for Python soon.
Sorting in C# using IComparable
using System;
using System.Collections;
using System.Reflection;
class Sort{
private class B : IComparable {
// Fields to be sorted
public int pages;
public string title;
// Initializer
public B ( int p, string t ){
title = t;
pages = p;
}
// The CompareTo method
public int CompareTo( object o ){
B k = (B) o;
if ( pages != k.pages ){
return pages - k.pages;
}
else
return title.CompareTo( k.title );
}
}
public string bookOrder( string books, int number ){
B[] book = new B[ number ];
string[] values = books.Split( ' ' );
// Parsing
for ( int i = 0; i < number; i++ ){
book[i] = new B(int.Parse( values[2*i] ), values[2*i+1] );
}
// Using Arrays.sort
Array.Sort( book );
// Return it in the format required.
String s = "";
for ( int i = 0; i < number; i++ ){
s += (int)book[i].pages + " " + book[i].title + " ";
}
return s.Trim();
}
}
I just uploaded to CodePlex my recent project called Package Maker 2008.
I build Package Maker so I can easily Create file package from changesets.
Package Maker 2008 version 1.0 works only for Web Projects.
http://www.codeplex.com/PackageMaker2008/
Enjoy
Hello Everyone,
Three days ago the Team System Master (Guy Kolbis :-) ) suggest me to open my own blog.
As you can see I adopt Guy's idea...
I getting a lot of requests to publish my Team System tools,
So in a few days I'll publish those tools from my blog.
Great weekend to all
Automate TFS Build Delete
The Team Foundation Build Server at one of our clients was getting out of hand.
We set up continuous integration so we are getting a lot of builds per day.
The server had hundreds of builds that we just didn't need hanging around anymore.
So we wrote an tool to automate the cleanup of TFS Builds.
After I finished developing the tool I noticed that it's much more comfortable to manage our Builds through this tool.
Simple statistics about all Builds and there status, fast way to enter Build Log, Build Drop Location, Changesets and of course delete them.
You can easily filter your Builds list by Date.( Example - Delete all builds before DD/MM/YYYY)

Team System Work Item Color Control
I've develop a "Color Control" for VSTS Work Items.
The "Color Control" (<Control Type="ColorControl" Label="" LabelPosition="Left" />) is placed in every Work Item and by the Work Item Type he takes the wanted color from an xml file located on the TFS.
In addition we create an "Combo Color Control".
This is similar to the "Color Control" except that colors are not by the Work Item Type but
for each value in the combo box the color changes.

Create Work Item After Build Success / Failure
In the last post I talked about Customize Build Number using TFSBuild.proj, now I'll show how to use TFSBuild.proj file for creating Work Item after build.
First thing is to add "CreateNewWorkItem" UsingTask TFSBuild.proj:
</Import>
<UsingTask TaskName="Microsoft.TeamFounadtion.Build.Tasks.CreateNewWorkItem" AssemblyFile="$(TeamBuildRefPath)\Microsoft.TeamFoundation.Build.Tasks.VersionControl.dll" />
WorkItemFieldValues
Using this property, you can specify the field values of the bug(or any wit you want to create).
For example:
</ItemGroup>
<PropertyGroup>
<WorkItemFieldValues>
Priority =1; Severity=High; Assigned To = Shai Raiten; Title = Build Task
</WorkItemFieldValues>
<WorkItemType>Task</WorkItemType>
</PropertyGroup>
MSBuild targets define how a MSBuild project is built
For all targets available enter here: Build Targets Table
AfterCompile = Run custom tasks after the code files are compiled.S
<Target Name="AfterCompile" Condition=" '$(BuildBreak)'!='true' and '$(IsDesktopBuild)'!='true' " >
<CreateNewWorkItem TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildId="$(BuildNumber)"
Description="Build Log : $(DropLocation)$(BuildNumber)\BuildLog.txt."
TeamProject="$(TeamProject)"
Title="Build - $(BuildNumber) completed successfully"
WorkItemFieldValues="$(WorkItemFieldValues)"
WorkItemType="$(WorkItemType)"
ContinueOnError="true" />
</Target>
On compile success the new work item fields value we be taken from the value you entered above.
On compile failure the new work item fields field value we be taken from the main PropertyGroup.
10 Steps To Customize Build Numbers
The steps that you must follow to customize a Team Foundation Build build definition with a task that generates build numbers.
- Access to the TFSBuild.proj file of the build definition you want to customize.
- By default, the TFSBuild.proj file is located in the folder $/MyTeamProject/TeamBuildTypes/MyBuildName in Team Foundation source control.
- A local workspace that contains your team project files and the build files on your local computer.
- Required Permissions.
- To perform this task, you must have the Administer a build and Administer workspaces permission set to Allow. You must also have the Check in and Check out permissions set to Allow.
Writing the Build Number Task
- Create a Visual C# class library called BuildNumberTask
- Add Reference to your project, Microsoft.Build.Framework and Microsoft.Build.Utilities
- Insert the following code to the class.cs.
using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
namespace BuildNumberGenerator
{
public class BuildNumberGenerator:Task
{
public override bool Execute()
{
m_buildNumber = DateTime.UtcNow.Ticks.ToString();
return true;
}
private string m_buildNumber;
[Output]
public string BuildNumber
{
get { return m_buildNumber; }
}
}
}
-
Build your class library to produce BuildNumberTask.dll.
-
Copy the built DLL to the local workspace folder that also contains the TFSBuild.proj file of your build definition.
-
Now you have to add BuildNumberTask.dll into the source control.
-
Open Visual Studio Command Prompt
-
Move to the location where the TFSBuild.proj file is stored (Step 5)
-
To add your file to source control type:
-
To check in your file to source control type:
-
Check out the TFSBuild.proj file.
-
Insert into TFSBuild.proj the UsingTask element immediately after the import statement:
-
To insert your task into the BuildNumberOverrideTarget target, add the following XML:
-
Save and Check in TFSBuild.proj.