Azure, Powershell, Professional

Leveraging PowerShell to migrate Azure DevOps Test Plans

Azure Test Plans are a great way to manage and track testing. It is fairly easy to user and easily integrates with other Azure DevOps feature such as a Product Backlog and an Azure Release Pipeline.

One shortcoming though is it’s not easy to migrate Test Plans between projects or between organizations. Luckily this is can be fairly straight forward when leveraging PowerShell.

At a high level what we need to do is call the Azure DevOps Test Plan APIs to retrieve a list of Test Plans. Then for each Test Plan call the Clone Operation telling Azure DevOps the Test Plan we are cloning and the Destination Project we are sending it to.

Before going forward set up PowerShell using an Azure Devops API Token. Once this is setup the following Powershell should be pretty straight forward as to what we are doing and migrate all the Test Plans over:

$AzureDevOpsPAT="TokenFromEarlierStep"
$OrganizationName = "yourOrgName"
$SourceProjectName = "sourceProjectName"
$DestinationProjectName= "destinationProjectName"
$DestinationAreaPath = "$DestinationProjectName"
$DestinationIterationPath = "$DestinationProjectName"
$AzureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")) }
$UriTestBase = "_apis/test/plans"
$UriListTestPlans = $UriOrga + $UriTestBase + "?filterActivePlans=true&api-version=5.0"
$UriOrga = "https://dev.azure.com/$($OrganizationName)/$($SourceProjectName)/" 
$response = Invoke-RestMethod -Uri $UriListTestPlans -Headers $AzureDevOpsAuthenicationHeader -Method Get -ContentType application/json;
$response.value | ForEach-Object{
$SourcePlanId = $_.id
$SourceTestPlanName = $_.name
$uriClone = $UriOrga + $UriTestBase+"/"+$SourcePlanId + "/cloneoperation?api-version=5.0-preview.2"

$cloneBody = @"
{
  "destinationTestPlan": {
    "name": "$SourceTestPlanName",
    "Project": {
      "Name": "$DestinationProjectName"
    }
  },
  "options": {
    "copyAncestorHierarchy": true,
    "copyAllSuites": true,
    "overrideParameters": {
      "System.AreaPath": "$DestinationAreaPath",
      "System.IterationPath":"$DestinationIterationPath"
    }
  },
  "suiteIds": [
    2
  ]
}
"@
Invoke-RestMethod -Uri $uriClone -Body $cloneBody -Headers $AzureDevOpsAuthenicationHeader -Method Post -ContentType application/json;
}