= Powershell: Azure DevOps API: Keep Forever =
**Summary**: Goal of the script is to check all my deployments in production and set the retain indefinitely / keep forever property to true if this is not done yet. \\
**Date**: Around 2022 \\
**Refactor**: 6 April 2025: Checked links and formatting. \\
{{tag>powershell azuredevops}}
The script below uses the following parts / useful techniques:
* List all projects
* List all deployments
* Get Releases
* The combined use of the $top parameter and a continuation token
= The Script =
Note that you need to change the first three variables.
# Define organization base url, PAT and API version variables
$orgUrl = "https://dev.azure.com/ORGNAME"
$releaseOrgUrl = "https://vsrm.dev.azure.com/ORGNAME"
$pat = "XXX"
$apiversion = "api-version=6.1-preview"
# Create header with PAT
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
$header = @{authorization = "Basic $token"}
# First list all projects
$projecturl = "$orgUrl/_apis/projects?$apiversion"
Write-Output "Projects url = $projecturl"
$projects = (Invoke-RestMethod -Uri $projecturl -Method GET -ContentType "application/json" -Headers $header).Value
# Override to test with 1 project
# $projects = $projects | where {$_.name -eq "projectname"}
ForEach ($project in $projects){
Write-Host "Project: $($project.name)"
# List all deployments
# Note that with the default settings you only get a maximum of 50 deployments per request, which can be changed using the $top parameter, to a max of 100. After which you need to use the continuationToken to loop through multiple requests and add the responses.
Write-Host "Evaluating deployments per 100: " -NoNewline
$deploymentbaseurl = "$releaseOrgUrl/$($project.name)/_apis/release/deployments?$apiversion&`$top=100"
$deploymenturl = $deploymentbaseurl
$deployresults = @()
do {
# Write-Output "Deployment url = $deploymenturl"
# Note: The ResponseHeadersVariable parameter was added in PS 6
$deployments = Invoke-RestMethod -Uri $deploymenturl -Method GET -ContentType "application/json" -Headers $header -ResponseHeadersVariable headers
# Add the deployments to the previous deployments, if any
$deployresults += $deployments.value
# Grab the continuation token from the webserver response, and change the deployment url accordingly
if ($headers["x-ms-continuationtoken"]){
$continuation = $headers["x-ms-continuationtoken"]
#write-host "Token: $continuation"
$deploymenturl = $deploymentbaseurl + "&continuationtoken=" + $continuation
}
Write-Host "." -NoNewline
} while ($headers["x-ms-continuationtoken"])
# Only select the successful deployments to production
$prddeployments = $deployresults | Select-Object release,deploymentStatus,releaseEnvironment,releaseDefinition | Where-Object {(($_.releaseEnvironment.name -eq "production") -AND ($_.deploymentStatus -eq "succeeded"))}
Write-Host "`nNumber of total deployments = $($deployresults.Count)"
Write-Host "Number of prod deployments = $($prddeployments.Count)"
# Check every production deployment if the retain forever flag is set to true
ForEach ($prddeploy in $prddeployments){
$releaseurl = "$releaseOrgUrl/$($project.name)/_apis/release/releases/$($prddeploy.release.id)?$apiversion"
#Write-Output "Release url = $releaseurl"
$keepforever = (Invoke-RestMethod -Uri $releaseurl -Method GET -ContentType "application/json" -Headers $header).keepforever
if (!$keepforever) {
Write-Host "Missing Retain Forever: " -ForegroundColor Red -NoNewline; Write-Host "$($prddeploy.release.webAccessUri)"
# Comment the next lines out if you first want to run without actually changing something
try{
$changeddeployment = Invoke-RestMethod -Uri $releaseurl -Method Patch -ContentType "application/json" -Headers $header -Body "{`"keepforever`":`"true`"}"
write-host "Deployment $($changeddeployment.name) (id:$($changeddeployment.id)) was set to keep forever: $($changeddeployment.keepForever)"
} catch {
write-host "Changing keep forever failed, please try to do manually: $($prddeploy.release.webAccessUri)"
Write-host $_.Exception.Message
}
}
}
}
= Useful Links =
* Rest API: https://docs.microsoft.com/en-us/rest/api/azure/devops/build/leases?view=azure-devops-rest-6.1
* List projects: https://docs.microsoft.com/en-us/rest/api/azure/devops/core/projects/list?view=azure-devops-rest-6.0
* List deployments: https://docs.microsoft.com/en-us/rest/api/azure/devops/release/deployments/list?view=azure-devops-rest-6.0
* Inspiration for continuationToken: # https://stackoverflow.com/questions/69345683/azure-devops-rest-api-top-parameter-in-powershell-script-is-not-working
* List releases: https://docs.microsoft.com/en-us/rest/api/azure/devops/release/releases/list?view=azure-devops-rest-6.0
//This wiki has been made possible by://