Change build definition branches with PowerShell

Problem:

I have a large number of build definitions I need to point to a different branch.

Solution:

Use the attached PowerShell script.

Explanation:

Today on a call with a customer I was asked how they could point hundreds of builds to a new branch.  My obvious answer was with PowerShell.  With PowerShell we can use the entire TFS API to script whatever we need.  The attached script defines an update-BuildBranch function that takes the following parameters:

$tfsUrl

This is the full URL to your Team Foundation Server collection. https://tfs.visualstudio.com/DefaultCollection/

$teamProject

This is the name of the Team Project that contains the desired build definition.

$buildDefinitionName

This is the name of the Build Definition to update or clone.

$from

This is the portion of the Source Control Folder value to search for. $/TeamProject/Branch

$to

This is the value to replace the $from value with. $/TeamProject/NewBranch

$update

If present the Build Definition is updated. If not a copy of the Build Definition is made. -update

 

function update-BuildBranch

{

    [CmdletBinding()]

    param(

        [string] $tfsUrl,

        [string] $teamProject,

        [string] $buildDefinitionName,

        [string] $from,

        [string] $to,

        [switch] $update

        )

 

    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")

    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")

 

    $teamProjectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsUrl)

    $buildServer = $teamProjectCollection.GetService([type]"Microsoft.TeamFoundation.Build.Client.IBuildServer")

    $buildDef = $buildServer.QueryBuildDefinitions($teamProject) | Where-Object { $_.Name -eq $buildDefinitionName }

 

    if($buildDef -eq $null)

    {

        Write-Error "Build Definition was not found"

        return;

    }

 

    if($from.StartsWith("$"))

    {

        $from = "\" + $from;

    }

 

    if($update.IsPresent)

    {

        foreach($mapping in $buildDef.Workspace.Mappings)

        {

            $original = $mapping.ServerItem

            $mapping.ServerItem = $original -replace $from, $to

            Write-Verbose "Updating $original to $($mapping.ServerItem)"

        }

 

        $buildDef.ProcessParameters = $buildDef.ProcessParameters -replace $from, $to;

 

        $buildDef.Save();

    }

    else

    {

        $branch = $to.Substring($to.LastIndexOf("/") + 1);

 

        # Find a name

        $count = 1;

        $newName = "$($buildDef.Name)_$branch"

 

        while(($buildServer.QueryBuildDefinitions($teamProject) | Where-Object { $_.Name -eq $newName }) -ne $null)

        {

            $newName = "$($buildDef.Name)_$branch`_$count"

            $count++;

        }

       

        Write-Verbose "Cloning build to $newName"

 

        $cloneDef = $buildServer.CreateBuildDefinition($teamProject);

 

        $cloneDef.BuildController = $buildDef.BuildController

        $cloneDef.BatchSize = $buildDef.BatchSize;

        $cloneDef.ContinuousIntegrationQuietPeriod = $buildDef.ContinuousIntegrationQuietPeriod;

        $cloneDef.ContinuousIntegrationType = $buildDef.ContinuousIntegrationType;

        $cloneDef.DefaultDropLocation = $buildDef.DefaultDropLocation;

        $cloneDef.Description = $buildDef.Description;

        $cloneDef.Enabled = $buildDef.Enabled;

        $cloneDef.Name = $newName;

        $cloneDef.Process = $buildDef.Process;

        $cloneDef.ProcessParameters = $buildDef.ProcessParameters -replace $from, $to;

        $cloneDef.QueueStatus = $buildDef.QueueStatus;

       

        $cloneDef.TriggerType = $buildDef.TriggerType;

 

        foreach($mapping in $buildDef.Workspace.Mappings)

        {

            $original = $mapping.ServerItem

            $newMapping = $original -replace $from, $to;

            $cloneDef.Workspace.AddMapping($newMapping, $mapping.LocalItem, $mapping.MappingType)

            Write-Verbose "Updating $original to $newMapping"

        }

 

        $cloneDef.Save();

    }

}

 

updateBuildBranch.ps1 (3KB)

Comments (6) -

  • Thank you Donovan!  Exactly what I was looking for.
  • Donovan,

    This script is exactly what I was looking for!

    I saw you at Ignite in Chicago and you really gave me the push I needed to use powershell to my advantage.

    -Thanks,
    Kurtis Orr
    • Hey Kurtis!  Glad this information was helpful.
  • Hi, Thanks for posting this blog. This is what I was looking for but I am running into an issue and get following error:
    Build Definition was not found
        + CategoryInfo          : NotSpecified: (Smile [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,CreateNewBuild.ps1

    It seems that it is not able to create the $buildServer object out of $teamProjectCollection.  This is my code block where I am running into issue:

           # AVRC_ETL/_apis/Release/definitions
       $tfsUrl = "http://server:8080/tfs/XVR/"
       $teamProject = "AVRC_ETL"
       $buildDefinitionName = "MS-BIEngineContent"
       $from =  "$/AVRC_ETL/ETL_DEV"
       $to = "$/AVRC_ETL/ETL_DEV/Dataset"
      
        [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")

        [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")



        $teamProjectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsUrl)
        write-output $teamProjectCollection

        $buildServer = $teamProjectCollection.GetService([type]"Microsoft.TeamFoundation.Build.Client.IBuildServer")
        write-output $buildServer
        
        $buildDef = $buildServer.QueryBuildDefinitions($teamProject) | Where-Object { $_.Name -eq $buildDefinitionName }

    # Write-Output $teamProject
    # write-Output $teamProjectCollection
    # Write-Output $buildDefinitionName
      write-Output $buildServer
       Write-Output "DEF: " $buildDef

        if($buildDef -eq $null)

        {

            Write-Error "Build Definition was not found"

            return;

        }
    • In the line
      $tfsUrl = "http://server:8080/tfs/XVR/"
      is XVR your collection name or project name?
      • XVR is the name of collection. So I see, I am passing collection name in the URL but also trying to get the $teamProjectCollection by using the ($tfsUrl) which already had collection in it.. Am I right? So I should remove the collection name from the $tfsUrl?

Add comment

Loading