Find unused projects
Last updated
This script will search for projects who haven't had a release created in the previous set number of days.
Please note, this script will exclude projects:
- Without any releases.
- Projects already disabled.
Usage
Provide values for the following:
- Octopus URL
- Octopus API Key
- Disable Old Projects - indicates if the projects should be set to disabled, default is $false
- Days Since Last Release - the number of days to allow before considering the project is inactive, default is 90
Script
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
$octopusUrl = "https://local.octopusdemos.app" ## Octopus URL to look at
$octopusApiKey = "YOUR API KEY" ## API key of user who has permissions to view all spaces, cancel tasks, and resubmit runbooks runs and deployments
$disableOldProjects = $false ## Tells the script to disable the projects that are older than the days since last release
$daysSinceLastRelease = 90 ## The number of days since the last release to be considered unused. Any project without a release created in [90] days is considered inactive.
$cachedResults = @{}
function Invoke-OctopusApi
{
param
(
$octopusUrl,
$endPoint,
$spaceId,
$apiKey,
$method,
$item,
$ignoreCache
)
$octopusUrlToUse = $OctopusUrl
if ($OctopusUrl.EndsWith("/"))
{
$octopusUrlToUse = $OctopusUrl.Substring(0, $OctopusUrl.Length - 1)
}
if ([string]::IsNullOrWhiteSpace($SpaceId))
{
$url = "$octopusUrlToUse/api/$EndPoint"
}
else
{
$url = "$octopusUrlToUse/api/$spaceId/$EndPoint"
}
try
{
if ($null -ne $item)
{
$body = $item | ConvertTo-Json -Depth 10
Write-Verbose $body
Write-Host "Invoking $method $url"
return Invoke-RestMethod -Method $method -Uri $url -Headers @{"X-Octopus-ApiKey" = "$ApiKey" } -Body $body -ContentType 'application/json; charset=utf-8'
}
if (($null -eq $ignoreCache -or $ignoreCache -eq $false) -and $method.ToUpper().Trim() -eq "GET")
{
Write-Verbose "Checking to see if $url is already in the cache"
if ($cachedResults.ContainsKey($url) -eq $true)
{
Write-Verbose "$url is already in the cache, returning the result"
return $cachedResults[$url]
}
}
else
{
Write-Verbose "Ignoring cache."
}
Write-Verbose "No data to post or put, calling bog standard invoke-restmethod for $url"
$result = Invoke-RestMethod -Method $method -Uri $url -Headers @{"X-Octopus-ApiKey" = "$ApiKey" } -ContentType 'application/json; charset=utf-8'
if ($cachedResults.ContainsKey($url) -eq $true)
{
$cachedResults.Remove($url)
}
Write-Verbose "Adding $url to the cache"
$cachedResults.add($url, $result)
return $result
}
catch
{
if ($null -ne $_.Exception.Response)
{
if ($_.Exception.Response.StatusCode -eq 401)
{
Write-Error "Unauthorized error returned from $url, please verify API key and try again"
}
elseif ($_.Exception.Response.statusCode -eq 403)
{
Write-Error "Forbidden error returned from $url, please verify API key and try again"
}
else
{
Write-Verbose -Message "Error calling $url $($_.Exception.Message) StatusCode: $($_.Exception.Response.StatusCode )"
}
}
else
{
Write-Verbose $_.Exception
}
}
Throw $_.Exception
}
$spaceList = Invoke-OctopusApi -octopusUrl $octopusUrl -apiKey $octopusApiKey -endPoint "spaces?skip=0&take=1000" -spaceId $null -method "GET"
$currentUtcTime = $(Get-Date).ToUniversalTime()
$oldProjectList = @()
foreach ($space in $spaceList.Items)
{
$projectList = Invoke-OctopusApi -octopusUrl $octopusUrl -apiKey $octopusApiKey -endPoint "projects?skip=0&take=10000" -spaceId $space.Id -method "GET"
foreach ($project in $projectList.Items)
{
if ($project.IsDisabled -eq $true)
{
Write-Verbose "Project $($project.Name) is already disabled."
continue
}
$releaseList = Invoke-OctopusApi -octopusUrl $octopusUrl -apiKey $octopusApiKey -endPoint "projects/$($project.Id)/releases" -spaceId $space.Id -method "GET"
if ($releaseList.Items.Count -le 0)
{
Write-Verbose "No releases found for $($project.Name)."
continue
}
$assembledDate = [datetime]::Parse($releaseList.Items[0].Assembled)
$assembledDate = $assembledDate.ToUniversalTime()
$dateDiff = $currentUtcTime - $assembledDate
if ($dateDiff.TotalDays -gt $daysSinceLastRelease)
{
$oldProjectList += "$($project.Name) - $($space.Name) last release was $($dateDiff.TotalDays) days ago."
if ($disableOldProjects -eq $true)
{
$project.IsDisabled = $true
$updatedProject = Invoke-OctopusApi -octopusUrl $octopusUrl -apiKey $octopusApiKey -endPoint "projects/$($project.Id)" -spaceId $space.Id -method "PUT" -Item $project
Write-Host "Set the project $($updatedProject.Name) to disabled."
}
}
}
}
Write-Host "The following projects were found to have no releases created in at least $daysSinceLastRelease days."
foreach ($project in $oldProjectList)
{
Write-Host " $project"
}
Need support? We're here to help.