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

Comments

  • Anonymous
    February 26, 2007
    James, I'm surprised this wasn't done in PowerShell!?!?!  Perhaps you can do it more elegantly than I did: param( [string] $serverName = $(throw 'serverName is required') ) begin { $tfs = get-tfs $serverName; $css = $tfs.css; $gss = $tfs.gss; } process { $results = new-object System.Collections.ArrayList $css.ListProjects() | % { $project = $; write-debug ('Checking TFS groups for project: {0}' -f $.Name); $gss.ListApplicationGroups($.Uri) | % { $group = $; write-debug ('  Checking TFS group: {0}' -f $.DisplayName) $gss.ReadIdentity(1, $.Sid, 1).Members | % { $identity = $gss.ReadIdentity(1, $_, 0); write-debug ('    Checking TFS group member: {0}' -f $identity.DisplayName) $memberIsGroup = $identity.SecurityGroup -or $identity.Type -eq 3 -or $identity.Type -eq 4; $item = new-object psobject; $projectName = ('return "{0}"' -f $project.Name) $groupName = ('return "{0}"' -f $group.DisplayName); $memberName = ('return "{0}"' -f $identity.DisplayName); $isGroup = ('return "{0}"' -f $memberIsGroup); $item | add-member scriptproperty "Project" $ExecutionContext.InvokeCommand.NewScriptBlock($projectName) $item | add-member scriptproperty "Group" $ExecutionContext.InvokeCommand.NewScriptBlock($groupName) $item | add-member scriptproperty "Member"  $ExecutionContext.InvokeCommand.NewScriptBlock($memberName) $item | add-member scriptproperty "IsGroup" $ExecutionContext.InvokeCommand.NewScriptBlock($isGroup) [void]$results.Add($item) } } } return $results; }

  • Anonymous
    February 26, 2007
    I didn't do it in PowerShell because the forum user needed it in C# (well, he said he needed it programmatically, and as much as I'd love to believe everyone's converted over to PowerShell, I'm not willing to believe it just yet :)

  • Anonymous
    February 27, 2007
    Eric Lee on Streams and Branches Part 1. Brian Harry on More TFS Channel 9 Videos. Howard Dierking...

  • Anonymous
    February 27, 2007
    Turns out, I misunderstood the initial forum post . Their goal wasn't to make sure all the team project