Last active
May 16, 2025 13:53
-
-
Save rfennell/b4453345f371f5f42dbd15611a893797 to your computer and use it in GitHub Desktop.
This script connects to an Azure DevOps organization using a Personal Access Token (PAT). It enumerates all projects within the organization, retrieves all pipelines for each project, and gathers details about each pipeline, including type (YAML or Classic), source repository, default branch, repository URL, and the status and time of the latest…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Retrieves pipeline information for all projects in an Azure DevOps organization and exports it to a CSV file. | |
.DESCRIPTION | |
This script connects to an Azure DevOps organization using a Personal Access Token (PAT). | |
It enumerates all projects within the organization, retrieves all pipelines for each project, | |
and gathers details about each pipeline, including type (YAML or Classic), source repository, | |
default branch, repository URL, and the status and time of the latest run. | |
The collected information is exported to a specified CSV file. | |
.PARAMETER organization | |
The name of the Azure DevOps organization. | |
.PARAMETER pat | |
The Personal Access Token (PAT) used for authentication with the Azure DevOps REST API. | |
.PARAMETER outputCsv | |
The file path for the output CSV file. | |
.NOTES | |
- Requires PowerShell and network access to Azure DevOps REST API. | |
- The PAT must have sufficient permissions to read projects, pipelines, and repositories. | |
- Handles both YAML and Classic pipelines. | |
- For YAML pipelines using Azure Repos Git, attempts to resolve the repository URL via the Azure DevOps API. | |
- The script processes all projects in the organization, not just a single project. | |
.EXAMPLE | |
.\get-azdo-builds.ps1 -organization "my-org" -pat "my-pat" -outputCsv "./pipelines.csv" | |
Retrieves pipeline information from all projects in the specified Azure DevOps organization and exports it to "pipelines.csv". | |
#> | |
# Azure DevOps organization and project details | |
param( | |
[string]$organization, | |
[string]$pat, | |
[string]$outputCsv | |
) | |
# Base64-encode the PAT for authentication | |
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat")) | |
# Get all team projects in the organization | |
$projectsUri = "https://dev.azure.com/$organization/_apis/projects?api-version=7.0" | |
Write-Host "Fetching list of projects from Azure DevOps..." | |
$projectsResult = Invoke-RestMethod -Uri $projectsUri -Headers @{Authorization = "Basic $base64AuthInfo"} | |
$projects = $projectsResult.value | |
Write-Host ("Found {0} projects." -f $projects.Count) | |
# Prepare an array to hold pipeline info | |
$pipelineInfoList = @() | |
foreach ($projectObj in $projects) { | |
$project = $projectObj.name | |
Write-Host ("\nProcessing project: {0}" -f $project) | |
# Get all pipelines for this project | |
$uri = "https://dev.azure.com/$organization/$project/_apis/pipelines?api-version=7.0" | |
Write-Host " Fetching pipelines..." | |
$pipelines = Invoke-RestMethod -Uri $uri -Headers @{Authorization = "Basic $base64AuthInfo"} | |
Write-Host (" Found {0} pipelines." -f $pipelines.count) | |
foreach ($pipeline in $pipelines.value) { | |
$pipelineId = $pipeline.id | |
$pipelineName = $pipeline.name | |
Write-Host (" Processing pipeline: {0} (ID: {1})..." -f $pipelineName, $pipelineId) | |
# Get pipeline details (for repository info) | |
$pipelineDetailsUri = "https://dev.azure.com/$organization/$project/_apis/pipelines/$($pipelineId)?api-version=7.0" | |
$pipelineDetails = Invoke-RestMethod -Uri $pipelineDetailsUri -Headers @{Authorization = "Basic $base64AuthInfo"} | |
# Handle both YAML and Classic pipelines | |
$designerJsonRepo = $null | |
$repo = $null | |
$pipelineType = $null | |
if ($pipelineDetails.configuration.PSObject.Properties.Name -contains 'designerJson') { | |
$designerJson = $pipelineDetails.configuration.designerJson | |
if ($designerJson.PSObject.Properties.Name -contains 'repository') { | |
$designerJsonRepo = $designerJson.repository | |
$pipelineType = $designerJson.type | |
} | |
} | |
if ($pipelineDetails.configuration.PSObject.Properties.Name -contains 'repository') { | |
$repo = $pipelineDetails.configuration.repository | |
$pipelineType = 'yaml' | |
} | |
if ($designerJsonRepo) { | |
$sourceType = $designerJsonRepo.type | |
$sourceBranch = $designerJsonRepo.defaultBranch | |
$sourceUrl = $designerJsonRepo.url | |
} elseif ($repo) { | |
$sourceType = $repo.type | |
$sourceBranch = $repo.defaultBranch | |
# For YAML pipelines with Azure Repos Git, get the repo URL from the repo id | |
if ($sourceType -eq 'azurereposgit' -and $pipelineType -eq 'yaml') { | |
$repoId = $repo.id | |
# Call the Azure DevOps Repositories API to get the repo details | |
$repoApiUri = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$($repoId)?api-version=7.0" | |
try { | |
$repoDetails = Invoke-RestMethod -Uri $repoApiUri -Headers @{Authorization = "Basic $base64AuthInfo"} | |
$sourceUrl = $repoDetails.webUrl | |
} catch { | |
$sourceUrl = 'Cannot resolve repo with ID ' + $repoId | |
} | |
} else { | |
$sourceUrl = $repo.url | |
} | |
} else { | |
$sourceType = '' | |
$sourceBranch = '' | |
$sourceUrl = '' | |
} | |
# Get latest run | |
$runsUri = "https://dev.azure.com/$organization/$project/_apis/pipelines/$($pipelineId)/runs?api-version=7.0&$top=1" | |
$runs = Invoke-RestMethod -Uri $runsUri -Headers @{Authorization = "Basic $base64AuthInfo"} | |
if ($runs.count -gt 0) { | |
$lastRun = $runs.value[0] | |
$lastRunTime = $lastRun.createdDate | |
$status = $lastRun.result | |
Write-Host (" Last run: {0} (Status: {1})" -f $lastRunTime, $status) | |
} else { | |
$lastRunTime = "Never" | |
$status = "N/A" | |
Write-Host " No runs found for this pipeline." | |
} | |
$pipelineInfo = [PSCustomObject]@{ | |
"Team Project" = $project | |
"Pipeline Name" = $pipelineName | |
"Definition Id" = $pipelineId | |
"Pipeline Type" = $pipelineType | |
"Source Type" = $sourceType | |
"Source Branch" = $sourceBranch | |
"Source URL" = $sourceUrl | |
"Last Run Time" = $lastRunTime | |
"Status" = $status | |
} | |
$pipelineInfoList += $pipelineInfo | |
} | |
} | |
# Export to CSV | |
Write-Host "\nExporting pipeline information to $outputCsv..." | |
$pipelineInfoList | Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8 | |
Write-Host "Pipeline information exported to $outputCsv" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment