So, basically, this script is your cleanup crew for your Azure DevOps repo. Giving everyone force-push rights to delete branches can be a bit risky. Over time, old branches pile up, and without a built-in Azure tool to handle the mess, your repo can start looking like a digital hoarder’s paradise.
This script is your broom, letting admins sweep up old branches safely and regularly, keeping things tidy without handing out keys to everyone. It’s a tidy-up hack for your repo, making everyone’s life a bit easier and your repo a lot neater.
param(
[string]$OrgName,
[string]$Project,
[string]$Pat,
[int]$CutoffDays,
[string[]]$Blacklist
)
$Bytes = [System.Text.Encoding]::ASCII.GetBytes(":$($Pat)")
$EncodedPAT = [System.Convert]::ToBase64String($Bytes)
$OrgUrl = "https://dev.azure.com/$OrgName"
$BaseUrl = "$OrgUrl/$Project/_apis"
$Repos = az repos list --project $Project --query "[].{name:name, id:id}" | ConvertFrom-Json
foreach($Repo in $Repos){
$Branches = az rest `
--method get `
--uri "$BaseUrl/git/repositories/$($Repo.id)/stats/branches?api-version=7.1-preview.1" `
--headers "Authorization=Basic $EncodedPAT" `
--query "value[].{name:name, lastPush:commit.author.date, id:commit.commitId}" `
| ConvertFrom-Json
$CutOffDate = (Get-Date).AddDays($CutoffDays)
# Filter the items
$StaleBranches = $Branches | Where-Object { (Get-Date $_.lastPush) -lt $CutOffDate }
foreach($Branch in $StaleBranches){
# Skip branches in the blacklist
if ($Blacklist -contains $Branch.name) {
Write-Output "Skipping $($Branch.name) as it is in the blacklist"
continue
}
Write-Warning "Deleting $($Branch.name) from $($Repo.name). Last commit was $($Branch.lastPush) ($(((Get-Date)-(Get-Date $Branch.lastPush)).Days) days ago)"
az repos ref delete --org $OrgUrl -p $Project -r $Repo.id --name "heads/$($Branch.name)" --object-id $Branch.id
}
}
Thanks to colleague for keeping standards high over here.