Working with branches and security inheritance in TFS

I just ran into some issues at a customer site. First of all it showed out that they had an incredible amount of branches (almost 2.500) and secondly they had a mess in these branches because security inheritance was turned off in all of them. Ok you think, does it matter? Well, if you’re using build automation it does, consider following.

Build agents are defined at collection level, each agent is running as a service with a service account and all these service accounts needs access to the version control to be able to get the source code it’s going to build. For that reason there’s a collection level group called “Project Collection Build Service Account”, this is where you add all the service accounts that should be able to build (get) the source code in all the projects hosted inside the collection. This is what you could consider as a basic default, add the service account to that group and by inheritance that group should have access to the whole version control, just like the groups “Project Collection Administrators” and the “Project Collection Build Administrators” have their access to all the projects.

If, on the other hand, you have some odd projects where they need a more tightened security, then they become a target of change. In that case you break the inheritance and modify it on a project level. And just like that, if you have a branch that needs a specific security level you break the inheritance on that single branch. That’s the way it should be done, using inheritance in most cases until it isn’t feasible, at that time you can break it and define something different.

Ok, back to the problem I ran into, how to solve the issue of almost 2.500 branches having no security inheritance and trying to apply build automation with the need of that inherited security. That’s where PowerShell and the TFS Rest API will be your absolutely best friend!

$cred = New-PSCredential -Username “domain\username” -Password “pa55w0rd”
$uri = “http://YourTfs:8080/tfs/DefaultCollection/_apis/tfvc/branches?includeChildren=true”
$rootBranches = Invoke-RestMethod $uri -Method Get -ContentType application/json -Credential $cred

 

That’s it, by running those three lines of code you’ll get a PSObject in return containing all the root branches including their child branches. Just to iterate them over and for each branch simply call the old TF.exe with correct parameters for applying inheritance. Following commandline will accomplish this.

tf.exe vc permission /inherit:yes /collection:YourCollectionUri TheBranchPath

 

Okay, so let’s put it all together into a script:

function New-PSCredential {
  param (
    [string] $Username,
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
    $Password
  )
  Set-StrictMode -Version ‘Latest’
  if($Password -is [string]) {
    $Password = ConvertTo-SecureString -AsPlainText -Force -String $Password
  }
  elseif($Password -isnot [securestring]) {
    Write-Error (‘Value for Password parameter must be a [String] or [System.Security.SecureString]. You passed a [{0}].’ -f $Password.GetType())
    return
  }
  return New-Object ‘Management.Automation.PsCredential’ $UserName, $Password
}
 
function Recurse {
  param(
    $branch,
    $tf,
    $collection
  )
  & “$tf” vc permission /inherit:yes /collection:$collection $($branch.path)
  $branch.children | ForEach-Object {
    Recurse $_ $tf $collection
  }
}
 
#Find latest version of TF.exe
$tf = (Get-ChildItem “C:\Program Files (x86)\Microsoft Visual Studio 1?.0\Common7\IDE\tf.exe” | Sort-Object CreationTime -Descending | Select-Object -First 1).FullName
if([string]::IsNullOrEmpty($tf)) {
  Write-Error “Can’t find TF.exe”
  exit
}
 
#Set some useful variables
$cred = New-PSCredential -Username “domain\user” -Password “pa55w0rd”
$collectionUri = “http://YourServer:8080/tfs/DefaultCollection”
$branchUri = “$collectionUri/_apis/tfvc/branches?includeChildren=true”
 
#Get all the root branches
$rootBranches = Invoke-RestMethod $branchUri -Method Get -ContentType application/json -Credential $cred
 
#Recursively run TF.exe on each one of them
$rootBranches.value | ForEach-Object {
  Recurse $_ $tf $collectionUri
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s