How to move build definitions in TFS to other projects using the REST API

The new build system in TFS or VSTS supports saving build definitions as templates. The problem is, that this only works inside a single TFS project. If you want to share your definition with other projects you have to use the REST API.

First you have to extract your current build definition. Get a list of all build definitions and check the ids.

$url = "https://<server>/tfs/DefaultCollection/ProjectName/_apis/build/definitions?api-version=2.0"
(Invoke-RestMethod -Uri $url -Method Get -UseDefaultCredentials -ContentType application/json).value

Then use this ID to get the full definition.

$url = "https://<server>/tfs/DefaultCollection/ProjectName/_apis/build/definitions/18"
$json = Invoke-RestMethod -Uri $url -Method Get -UseDefaultCredentials -ContentType application/json

Now save the json to a file and remove all the clutter like _links, revision etc. I’ve marked all the sections that you can remove in the following picture.


Then search for your project name and replace it with __ProjectName__.

That’s it. You can now use the following PowerShell to create the build definition in any project. The script loads the json for the build from a file, replaces the project name with the parameter and then creates the build definition in the project.

$json = Get-Content .\Build.json
$json = $json.Replace("__ProjectName__", $ProjectName) 

$url = "https://<server>/tfs/DefaultCollection/$ProjectName/_apis/build/definitions?api-version=2.0"
Invoke-RestMethod -Uri $url -Method Post -UseDefaultCredentials -Body $json -ContentType application/json

See this post if you want to use the script with VSTS. In this case you have to create a personal Access token.

Update: There is now a ExportImportBuildDefinition Extension available in the market place from Utkarsh Shigihalli. You can still use the REST API if you want to template your builds or move them from TFS to VSTS or vice versa.


  1. Hi Michael,

    I am trying to update the build definition which is very similar to creating the build definition. I am using PUT to update the build definition as per the documentation –

    It is not working for me – It throws an error –
    Invoke-RestMethod : {“$id”:”1″,”innerException”:null,”message”:”The collection must contain at least one
    element.\r\nParameter name: definition.Options.Inputs”,”typeName”:”System.ArgumentException, mscorlib,
    Version=, Culture=neutral,
    At C:\vnext\getbd.ps1:17 char:1
    + Invoke-RestMethod -uri “http://alm:8080/tfs/boc_projects/Build/_apis/bu …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

    Unable to figure out the cause for this issue. Appreciate your help on this!


      1. Hi,
        I have the same problem: getting an existing build definition using REST API then trying to post it back with PUT.

        Narrowing down the problem it seems something wrong with the “options” object from the returned json; I can update the build definition only by removing it.

  2. Can be automated like this:

    Set-StrictMode -Version Latest

    $Server = “http://tfs:8080/tfs”;
    $ProjectSource = “ProjectSrc”;
    $ProjectDestination = “ProjectDst”;

    $Url = “$Server/DefaultCollection/$ProjectSource/_apis/build/definitions?api-version=2.0&type=build”;
    $BuildDefinitions = Invoke-RestMethod -Uri $Url -Method Get -UseDefaultCredentials -ContentType application/json;

    foreach ($BuildDefinition in $BuildDefinitions.value) {
    foreach ($id in $ {
    $urlget = “$Server/DefaultCollection/$ProjectSource/_apis/build/definitions/$id”;
    $json = Invoke-RestMethod -Uri $urlget -Method Get -UseDefaultCredentials -ContentType application/json;
    $postJson = ($json | ConvertTo-Json -Depth 3).Replace($ProjectSource, $ProjectDestination);
    $urlpost = “$Server/DefaultCollection/$ProjectDestination/_apis/build/definitions?api-version=2.0”
    $response =
    try {
    Invoke-RestMethod -Uri $urlpost -Method Post -UseDefaultCredentials -Body $postJson -ContentType application/json
    $result = $_.Exception.Response.GetResponseStream()
    $reader = New-Object System.IO.StreamReader($result)
    $reader.BaseStream.Position = 0
    $responseBody = $reader.ReadToEnd();
    [System.Tuple]::Create($_.Exception.Response ,$responseBody)
    if ([int]$response.Item1.StatusCode -ne 200) {
    $responseStatusCode = [int]$response.Item1.StatusCode;
    $responseMessage = ($response.Item2 | ConvertFrom-Json).message;
    Write-Error “Failed to import build with id $id.
    Response status code: $responseStatusCode.
    Message: $responseMessage.”;

Leave a Reply

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

You are commenting using your 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