Making sure your team project's groups only contain groups

I know, the title sounds a little odd. :)

Got a question in the forums:

i need to make sure that all the projects in TFS should have only group accounts

[NOTE: code is attached, so you don't have to copy-paste from the blog post itself]

For this, we'll use both ICommonStructureService (aka CSS) and IGroupSecurityService (aka GSS).  The flow will basically be:

  • Find all the team projects
    • For each of them, get all the groups
      • For each of them, check all the members for whether it's a group or not

First, we need to know all the project URI's from ICommonStructureService since that's the project identifier used in the IGroupSecurityService calls.  This is basically the same call as I made in the blog post to list all your team projects.

     TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(args[0]);
    ICommonStructureService css = (ICommonStructureService)tfs.GetService(typeof(ICommonStructureService));
    IGroupSecurityService gss = (IGroupSecurityService)tfs.GetService(typeof(IGroupSecurityService));
    foreach (ProjectInfo projectInfo in css.ListProjects())
    {
        Console.WriteLine("Checking TFS security groups for team project {0}", projectInfo.Name);

Then, for each project URI, we'll ask GSS for the application groups ("Readers", "Contributors", etc.) for that team project.

     Identity[] projectGroups = gss.ListApplicationGroups(projectInfo.Uri);
    foreach (Identity projectGroup in projectGroups)
    {
        Console.WriteLine("    Checking TFS security group {0}", projectGroup.DisplayName);

Then, for each group we'll get the list of direct members and check them.

     Identity directMembers = gss.ReadIdentity(SearchFactor.Sid, projectGroup.Sid, QueryMembership.Direct);
    foreach (string memberSid in directMembers.Members)
    {
        Identity member = gss.ReadIdentity(SearchFactor.Sid, memberSid, QueryMembership.None);
        Console.WriteLine("        Checking member {0}", member.DisplayName);

Now, we just need the right check to perform.  There's actually a few different kinds of meaning for the word "group", so we'll check each of them - any version of "group" will qualify as a group for us.

     if (member.SecurityGroup || 
        member.Type == IdentityType.WindowsGroup ||
        member.Type == IdentityType.ApplicationGroup)
    {
        Console.WriteLine("            Member is a group");
    }
    else
    {
        Console.Error.WriteLine("*** FAILED: member {0} of team project {1} group {2} is not a group!",
            member.DisplayName, projectInfo.Name, projectGroup.DisplayName);
    }

And there you go - you should be able to run this against your TFS (if you have the same kind of policy) and check out any policy "violations" you have.

Note that this only checks team project groups - your global groups (for instance, service accounts) will definitely have non-group members, but that's intentional and part of how TFS functions :)

CheckTfsGroups.zip