Hi @Benjamin Slack,
Welcome to the Microsoft Q&A Platform! Thank you for asking your question here.
You can get all run IDs, test case IDs, execution dates, and outcomes for a test plan using either the Azure DevOps Test Management REST API (good for scripting/exports) or the Analytics OData endpoint (better for dashboards and Power BI). Both approaches are covered below.
Approach 1 – REST API (PowerShell / scripting)
Step 1 – Get all runs for your test plan
GET https://dev.azure.com/{organization}/{project}/_apis/test/runs?planId={planId}&api-version=7.1
Each item in the response includes the run's id, name, state, and completedDate.
Step 2 – Get results for each run
GET https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/results?api-version=7.1
Each result includes:
-
testCase.id– the test case ID -
outcome– Passed, Failed, Blocked, etc. -
startedDate/completedDate– execution timestamps
Pagination note: This endpoint returns a maximum of 100 results per call. Use
$topand$skipto page through all records if any run contains more than 100 results — otherwise data will be silently truncated.
PowerShell Script (with pagination)
# Variables
$org = "https://dev.azure.com/yourOrg"
$project = "yourProject"
$planId = 42
$pat = "YOUR_PERSONAL_ACCESS_TOKEN"
$base64Auth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = @{ Authorization = "Basic $base64Auth" }
# Step 1 – Get all runs for the plan
$runsUrl = "$org/$project/_apis/test/runs?planId=$planId&api-version=7.1"
$runs = (Invoke-RestMethod -Uri $runsUrl -Headers $headers).value
# Step 2 – Get results per run (with pagination)
$allResults = foreach ($run in $runs) {
$skip = 0; $top = 100
do {
$url = "$org/$project/_apis/test/Runs/$($run.id)/results?`$top=$top&`$skip=$skip&api-version=7.1"
$batch = (Invoke-RestMethod -Uri $url -Headers $headers).value
foreach ($res in $batch) {
[PSCustomObject]@{
RunId = $run.id
RunName = $run.name
TestCaseId = $res.testCase.id
Outcome = $res.outcome
StartedDate = $res.startedDate
CompletedDate = $res.completedDate
}
}
$skip += $top
} while ($batch.Count -eq $top)
}
# Step 3 – Export to CSV
$allResults | Export-Csv -Path ".\TestPlan_${planId}_Results.csv" -NoTypeInformation
Approach 2 – Analytics OData (best for Power BI / dashboards)
If you need this data for ongoing reporting, the Analytics OData endpoint is more efficient. It lets you query all execution history for a test plan in a single request, without looping through each run.
Note: Analytics for Azure DevOps testing requires v3.0-preview or v4.0-preview of the OData API. The
TestResultsentity does not exposeTestPlanIddirectly, so there are two ways to approach this depending on your goal.
Option A – Use TestPointHistorySnapshot (filter directly by TestPlanId)
This is the simplest approach when you want to filter by plan ID without first looking up run IDs.
Step 1 – Open your browser or Power BI and call the following URL:
https://analytics.dev.azure.com/{organization}/{project}/_odata/v4.0-preview/TestPointHistorySnapshot
?$filter=TestPlanId eq {planId}
&$select=TestPlanId,TestCaseId,ResultOutcome
&$expand=Date($select=Date)
This returns one record per test point execution with:
-
TestCaseId– ID of the test case executed -
ResultOutcome– Passed, Failed, Blocked, etc. -
Date– the execution date (expanded from theDateSKnavigation property)
Step 2 – To also include the Run ID, expand the TestRun navigation property:
https://analytics.dev.azure.com/{organization}/{project}/_odata/v4.0-preview/TestPointHistorySnapshot
?$filter=TestPlanId eq {planId}
&$select=TestPlanId,TestCaseId,ResultOutcome
&$expand=Date($select=Date),TestRun($select=TestRunId,Title)
Option B – Use TestResults (filter by a list of TestRunIds)
Use this when you already have your run IDs (e.g. from Step 1 of Approach 1 above) and want the full granular result detail.
Step 1 – Build your run ID list from the REST API (as shown in Approach 1, Step 1), then use it in the OData filter:
https://analytics.dev.azure.com/{organization}/{project}/_odata/v4.0-preview/TestResults
?$filter=TestRunId in (101, 102, 103)
&$select=TestRunId,Outcome,StartedDate,CompletedDate
&$expand=Test($select=TestCaseReferenceId,TestName)
This returns:
-
TestRunId– the run the result belongs to -
Outcome– Passed, Failed, Inconclusive, etc. (15 possible values) -
StartedDate/CompletedDate– execution timestamps -
Test.TestCaseReferenceId– the test case ID -
Test.TestName– human-readable test name
Step 2 – Test the query in your browser first. Install a JSON formatter extension (available for Chrome and Edge) to read the output easily before wiring it into Power BI.
Step 3 – Connect to Power BI. In Power BI Desktop:
- Select Get Data → OData feed
- Paste the query URL above (converted to a single line)
- Authenticate with your Azure DevOps credentials
- Expand the
Testcolumn to surfaceTestCaseReferenceIdandTestName
References
- Test Runs – List (REST API)
- Test Results – List (REST API)
- Metadata reference for Test Plans Analytics (TestResults, TestPointHistorySnapshot)
- Construct OData queries for Analytics
- Connect Power BI to Analytics via OData
Let me know if this helps in comments.
Note: This answer is drafted with the help of AI systems.