Can I export azure devops pipelines run history using Powershell? - powershell

So what I want to know is if its possible to generate a report that will tell us all the pipelines that have been run in the past month, how long they took, any failures.
If so, how can I do it?
Here is some script iv got so far
$strURL = "https://dev.azure.com/{chealey}/{personal test}/_apis/build/builds?api-version=5.1"
$filePath="D:\"
$fileName=$filePath+"\pipeline.json"
$pipeline = Invoke-RestMethod -Uri $strURL -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
} -Method GET -OutFile $fileName

You can RUNS Rest Api: https://learn.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/list?view=azure-devops-rest-6.1
As example:
$user = ""
$token = $env:SYSTEM_ACCESSTOKEN
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = $env:SYSTEM_COLLECTIONURI
$teamProject = $env:SYSTEM_TEAMPROJECT
$restApiGetBuildDefinitions = "$orgUrl/$teamProject/_apis/build/definitions?api-version=6.1-preview.7"
$restApiGetBuildRunsTemplate = "$orgUrl/$teamProject/_apis/pipelines/{BUILD_DEF_ID}/runs?api-version=6.1-preview.1"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
$buildDefs = InvokeGetRequest $restApiGetBuildDefinitions
foreach ($buildDef in $buildDefs.value)
{
$restApiGetBuildRuns = $restApiGetBuildRunsTemplate -replace "{BUILD_DEF_ID}", $buildDef.id
$buildRuns = InvokeGetRequest $restApiGetBuildRuns
if ($buildRuns.count -gt 0)
{
Write-Host "Build Definition:" $buildDef.name
Write-Host "| Run Id | Start Date | Finish Date | Result |"
Write-Host "|--------|------------|-------------|--------|"
foreach ($buildRun in $buildRuns.value)
{
Write-Host "|" $buildRun.id "|" $buildRun.createdDate "|" $buildRun.finishedDate "|" $buildRun.result "|"
}
}
}

Related

create multiple projects error Azure DevOps rest api

I am using a rest API powershell to create multiple projects in azure devops. Writing my script in below way but it fails.
Any guidance on how I can construct my script to pick up multiple names?
'
$connectionToken="token"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$ProjectUrl = "url
$Body = #{
name = #{'TestProjectCreation1','test1','test2'
}
description = 'Frabrikam travel app for Windows Phone'
capabilities = #{
versioncontrol = #{
sourceControlType = 'Git'
}
processTemplate = #{
templateTypeId = 'template id'
}
}
} | ConvertTo-Json
$projectscreated = Invoke-RestMethod -Uri $ProjectUrl -Method Post -ContentType "application/json" -Headers #{
Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $Body
'
According to your description, you could create a new array for projects and foreach the project to create: scrpit like:
$url='https://dev.azure.com/{org}/_apis/projects?api-version=6.0'
$connectionToken="{PAT}"
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$projects= #('TestProjectCreation1','test1','test2')
Foreach($prject in $projects){
$body="
{
`"name`": `"$prject`",
`"capabilities`": {
`"versioncontrol`": {
`"sourceControlType`": `"Git`"
},
`"processTemplate`": {
`"templateTypeId`": `"6b724908-ef14-45cf-84f8-768b5384da45`"
}
}
}
"
$response= Invoke-RestMethod -Uri $url -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
}

Invoke-RestMethod from PowerShellScript doesn't work but work from commandline

I am trying to invoke a rest method from powershell script to get git changes from azure repo. When i run the whole process one by one command it works but when i try to run the whole script by writing a powershell script it doesn't work as expected giving empty output. can anyone tell what could be the problem here
$url = "https://dev.azure.com/<Org_Name>/<Project_Name>/_apis/git/repositories/<RepoID>/commits/$(Build.SourceVersion)/changes?api-version=5.1"
$userName = "Username"
$password = "<PAT>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $userName,$password)))
$result = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $base64AuthInfo"} -Method GET
Write-Host $result
$changesFolders = $result.changes | Where-Object {$_.item.gitObjectType -eq "tree"} | Select-Object -Property{$_.item.Path}
foreach($path in $changesFolders)
{
Write-Host $path
}
Write-Host $changesFolder
I am not sure how but i tried Invoke-webRequest instead of Invoke-RestMethod and it worked
But I had to make some changes in the header as well otherwise it was hitting the endpoint but still giving 203 status
$headers = #{
Authorization=("Basic" + [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$PAT")));
ContentType="application/json"
}
$result = Invoke-webRequest -Uri $url -Headers $header -Method GET
Write-Host $result.StatusCode
Gives result and status code 200 as expected
note: without adding a colon before password/PAT while converting to base64string will throw 203 status
The following example is working. Additionally, you can paste our resulting URL into the browser and check the answer from your org.
$user = ""
$token = "PAT"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "ORG"
$teamProject = "PROJECT"
$repoName = "REPONAME"
$commitId = "COMMITID"
$restApiGetCommit = "$orgUrl/$teamProject/_apis/git/repositories/$repoName/commits/$commitId/changes?api-version=5.1"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
Write-Host "Url" $restApiGetCommit
$commitInfo = InvokeGetRequest $restApiGetCommit
Write-Host "Commit: " $commitInfo.changes
foreach($path in $commitInfo.changes)
{
Write-Host "Path" $path.item.path
}

How do I get Build ID of an In progress Pipeline in Azure DevOps

Am triggering a build Pipeline from a release Pipeline as a first task through an API call and that doesn't have any Issue.
Second Task - Pipeline needs to wait Until the triggered Pipeline from the first task is completed and then go to Third Task. How do i achieve It ?
I have tried below in a powershell task to get the Build ID from the running pipeline and tried to wait through a loop, but am unable to get the Build Id
First Task to trigger a Build Pipeline
curl -L -X POST 'https://dev.azure.com/Org/project/_apis/build/builds?definitionId-1549&api-version=6.1-preview.6' -H 'Authorization: $(ADO_BASIC_AUTH)' -H 'Content-Type: application/json' --data '{"definition": {"id": 1549}}'
Second Task as you Suggested
$B64Pat = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$(ADO_BASIC_AUTH)"))
$header = #{ Authorization = "Basic $B64Pat" }
$continueCurrent = $true
$uriGetActiveBuilds1 = "https://dev.azure.com/org/project/_apis/build/builds?definitions=1549&statusFilter=inProgress,notStarted&api-version=5.1"
do
{
$continueCurrent = $true
$resultStatus = Invoke-RestMethod -Uri $uriGetActiveBuilds1 -Method Get -ContentType "application/json" -Headers $header
if ($resultStatus.count -gt 0)
{
$continueCurrent = $false
Write-Host " . "
Start-Sleep -s 10
}
}while($continueCurrent -eq $false)
Write-Host "Continue task"
The Second keeps waiting even If the Build Pipeline triggered from the First Task is completed
Output of my Pipeline
How do I get Build ID of an In progress Pipeline in Azure DevOps
The idea to solve this request can be:
Add a task to get the latest build id of the build pipeline before
the first task of the release pipeline (triggering a build pipeline)
Then get latest Id of the build pipeline again in the second task
after executing the first task.
If it is the same as the previous one, it means that the build
pipeline has not been running. Wait for 30 seconds.
If the ID is different, it means that the newly triggered build
pipeline has started running. We only need to determine whether the
status of the latest pipeline is complete
The REST API scripts to get the latest build id before your first task:
$connectionToken="$(PAT)"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$BuildPipelineUrl = "https://dev.azure.com/<YourOrganization>/<YourProject>/_apis/build/builds?definitions=173&`$top=1&api-version=6.0"
Write-Host "URL: $BuildPipelineUrl"
$BuildPipelineInfo = (Invoke-RestMethod -Uri $BuildPipelineUrl -Method Get -UseDefaultCredential -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
$LatestBuldId = $BuildPipelineInfo.value.id
Write-Host "LatestBuldId = $LatestBuldId"
Write-Host "##vso[task.setvariable variable=OldBuldPipelineId]$LatestBuldId"
The REST API scripts to get the latest build id and check the build status after your second task:
$connectionToken = "$(PAT)"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$success = $false
$count = 0
do{
try{
$Secondurl = "https://dev.azure.com/<YourOrganization>/<YourProject>/_apis/build/builds?definitions=173&`$top=1&api-version=6.0"
$NewBuildPipelineInfo = Invoke-RestMethod -Method Get -ContentType application/json -Uri $Secondurl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$NewBuildPipelineId = $NewBuildPipelineInfo.value.id
$NewBuildPipelinestatus = $NewBuildPipelineInfo.value.status
write-output $NewBuildPipelineId | ConvertTo-Json -Depth 100
write-output $NewBuildPipelinestatus | ConvertTo-Json -Depth 100
if($NewBuildPipelineId -eq '$(OldBuldPipelineId)') {
Write-output "Wait for new piepine trigger in 30 seconds"
Start-sleep -Seconds 30
} else {
Write-Host "New Pipeline was triggered"
if($NewBuildPipelinestatus -ne '"completed"') {
Write-output "wait forpipeline complete,Next attempt in 30 seconds"
Start-sleep -Seconds 30
}
else{
write-output "Pipeline complete"
$success = $true
}
}
}
catch{
Write-output "catch - Next attempt in 30 seconds"
write-output "1"
Start-sleep -Seconds 30
}
$count++
}until($count -eq 2000 -or $success)
if(-not($success)){exit}
The test result:
Update:
You can use another way. Add to your release a new variable:
Then use it in the script to define the build Id and get the status only of the queued build.
Run the build and pass build id:
$user = ""
$token = "<pat>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "https://dev.azure.com/<org>"
$teamProject = "<team_project>"
$buildDefId = <build_definition_id>
$body = '{"definition":{"id":<dev_id>}}' -replace "<dev_id>", $buildDefId
$uriRunBuild = "$orgUrl/$teamProject/_apis/build/builds?api-version=5.1"
$resultQueue = Invoke-RestMethod -Uri $uriRunBuild -Method Post -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$buildId = $resultQueue.Id
Write-Host "Build Id: $buildId"
Write-Host "##vso[task.setvariable variable=Custom.BuildId]$buildId"
Then use the build id to get the build status:
$user = ""
$token = "<pat>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "https://dev.azure.com/<org>"
$teamProject = "<team_project>"
$uriGetBuild = "$orgUrl/$teamProject/_apis/build/builds/$(Custom.BuildId)?api-version=5.1"
$uriGetBuild
$buildStatus = ""
do
{
$buildResult = Invoke-RestMethod -Uri $uriGetBuild -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$buildStatus = $buildResult.status
if ($buildStatus -ne "completed")
{
Write-Host " . "
Start-Sleep -s 2
}
}while($buildStatus -ne "completed")
Write-Host "Continue task"
One way
What do you see when you call Write-Host $result.latestBuild.id?
The Other way
You can add the status filter = inProgress
Small example:
First task. Run build:
$user = ""
$token = "<pat>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "https://dev.azure.com/<org>"
$teamProject = "<team_project>"
$buildDefId = <build_definition_id>
$body = '{"definition":{"id":<dev_id>}}' -replace "<dev_id>", $buildDefId
$continueCurrent = $true
$uriRunBuild = "$orgUrl/$teamProject/_apis/build/builds?api-version=5.1"
$resultQueue = Invoke-RestMethod -Uri $uriRunBuild -Method Post -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
Write-Host "Build Id" $resultQueue.Id
Second task. Wait for build of some build definition
$user = ""
$token = "<pat>"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = "https://dev.azure.com/<org>"
$teamProject = "<project>"
$buildDefId = <build_definition_id>
$continueCurrent = $true
$uriGetActiveBuilds = "$orgUrl/$teamProject/_apis/build/builds?definitions=$buildDefId&statusFilter=inProgress,notStarted&api-version=5.1"
do
{
$continueCurrent = $true
$resultStatus = Invoke-RestMethod -Uri $uriGetActiveBuilds -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
#$resultStatus.value
if ($resultStatus.count -gt 0)
{
$continueCurrent = $false
Write-Host " . "
Start-Sleep -s 2
}
}while($continueCurrent -eq $false)
Write-Host "Continue task"

Run an Azure Pipeline through API

I have done something to queue/build my pipelines in Azure through API. Now I am in need to run my pipelines through API. Hereby I attached my code for building/queuing pipeline.
$body = '
{
"definition": {
"id": 1
}
}
'
write-host "`n"
$bodyJson=$body
write-host $bodyJson -ForegroundColor Cyan
Write-Output $bodyJson | ConvertFrom-JSON
write-output $bodyJson
$bodyString=$bodyJson | ConvertTo-Json
write-host $bodyString -foregroundcolor green
$user="name"
$personalToken = "token"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personaltoken)"))
$Uri = "https://dev.azure.com/demoworldDemoworld/talentstogether/_apis/build/builds?api-version=5.1"
$buildresponse = Invoke-RestMethod -Method Post -UseDefaultCredentials -ContentType application/json -Uri $Uri -Body $bodyJson -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host $buildresponse
Kindly help me to run my pipelines through API in a similar way.
Please try the following script:
Param(
[string]$orgurl = "https://dev.azure.com/{organization}",
[string]$projectName = "0508-t",
[string]$BuildDefinitionId = "166",
[string]$user = "",
[string]$token = "PAT"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
function CreateJsonBody
{
$value = #"
{
"definition": {
"id": $BuildDefinitionId
}
}
"#
return $value
}
$json = CreateJsonBody
$uri = "$($orgurl)/$($projectName)/_apis/build/builds?api-version=5.1"
$buildresponse = Invoke-RestMethod -Uri $uri -Method Post -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
Write-Host $buildresponse

Error while cloning build definitions using REST API

I am trying to clone all the build definitions in VSTS using powershell REST API method. However, i am facing below error. Sharing the code and error which might be useful.
CODE:
Clear-Host
$buildToCloneName = $buildWeWant
$newBuildName = $buildWeWant-Clone
$user = "xxxxxxx"
$accessToken="xxxxxxxx"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$accessToken)))
$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI = "https://xxxxx.visualstudio.com/"
$env:SYSTEM_TEAMPROJECTID = "xxxxxxx"
"Getting all bulid definitions"
$allSuitesBuildUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions?api-version=2.0"
$allSuitedBuilds = Invoke-RestMethod -Uri $allSuitesBuildUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
foreach($buildDetails in $allSuitedBuilds.value){
$buildWeWant = $buildDetails
$buildId = $buildWeWant."id"
[int]$buildIdTest = $null
if(![int]::TryParse($buildId, [ref]$buildIdTest))
{
throw [Exception] "ERROR: NO BUILD ID FOUND"
}
"Getting the exact definition for the build"
# You can see this in the browser using xxxxxxxxxx
$thisBuildDefUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions/" + $buildId + "?api-version=2.0"
$thisBuildDefUrl
$thisBuildDef = Invoke-RestMethod -Uri $thisBuildDefUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
## Create a name for the clone by prefixing "_Clone" to the build name
"Assigning a new name"
$thisBuildDef.Name = $buildWeWant."id"."_Clone"
"Creating a clone build with name $newBuildName"
$defAsJson = $thisBuildDef | ConvertTo-Json -Depth 100
$newBuildDefUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions?api-version=2.0"
$newBuildDef = Invoke-RestMethod -Uri $thisBuildDefUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method Post -Body $defAsJson -ContentType "application/json" -ErrorAction Stop
$newBuildDefAsJson = $newBuildDef | ConvertTo-Json -Depth 100
$newBuildDefAsJson
"New Build Created"
$newBuildDef.Name
}
ERROR:
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value
cannot be null.\r\nParameter name:
definition.Name","typeName":"System.ArgumentNullException, mscorlib,
Version=14.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
At line:42 char:24
+ ... wBuildDef = Invoke-RestMethod -Uri $thisBuildDefUrl -Headers #{Author ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebExceptio n
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
You can prepare the header separately other than that of inline definition
Clear-Host
$buildToCloneName = $buildWeWant
$newBuildName = $buildWeWant-Clone
$user = "xxxxxxx"
$accessToken = "xxxxxxxx"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $accessToken)))
$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI = "https://xxxxx.visualstudio.com/"
$env:SYSTEM_TEAMPROJECTID = "xxxxxxx"
"Getting all bulid definitions"
$allSuitesBuildUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions?api-version=2.0"
$allSuitedBuilds = Invoke-RestMethod -Uri $allSuitesBuildUrl -Headers #{Authorization = ("Basic {0}" -f $base64AuthInfo) }
foreach ($buildDetails in $allSuitedBuilds.value) {
$buildWeWant = $buildDetails
$buildId = $buildWeWant."id"
[int]$buildIdTest = $null
if (![int]::TryParse($buildId, [ref]$buildIdTest)) {
throw [Exception] "ERROR: NO BUILD ID FOUND"
}
"Getting the exact definition for the build"
# You can see this in the browser using xxxxxxxxxx
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $base64AuthInfo")
$headers.Add("Content-Type", "application/json")
$thisBuildDefUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions/" + $buildId + "?api-version=2.0"
$thisBuildDefUrl
$thisBuildDef = Invoke-RestMethod -Uri $thisBuildDefUrl -Headers $headers
## Create a name for the clone by prefixing "_Clone" to the build name
"Assigning a new name"
$thisBuildDef.Name = $buildWeWant."id"."_Clone"
"Creating a clone build with name $newBuildName"
$defAsJson = $thisBuildDef | ConvertTo-Json -Depth 100
$newBuildDefUrl = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$($env:SYSTEM_TEAMPROJECTID)/_apis/build/definitions?api-version=2.0"
$newBuildDef = Invoke-RestMethod -Uri $thisBuildDefUrl -Headers $headers -Method Post -Body $defAsJson -ContentType "application/json" -ErrorAction Stop
$newBuildDefAsJson = $newBuildDef | ConvertTo-Json -Depth 100
$newBuildDefAsJson
"New Build Created"
$newBuildDef.Name
}