The Octopus Web Portal allows you to see what deployments have gone out to a specific deployment target, but it doesn’t provide you with a list of deployments for all the deployment targets in a role. This script demonstrates how to generate such a report.
Please note: The report is generated as a CSV file, formatting was added to the screenshot to make it easier to read.
Usage
Provide values for the following:
- Octopus URL
- Octopus API Key
- Report Path
- Space Name
- Target Role
- Days to Query
PowerShell (REST API)
$octopusUrl = "https://your-octopus-url"
$octopusApiKey = "API-YOUR-KEY"
$reportPath = "./Report.csv"
$spaceName = "Default"
$targetRole = "hello-world"
$daysToQuery = 365
$cachedResults = @{}
function Write-OctopusVerbose
{
param($message)
Write-Host $message
}
function Write-OctopusInformation
{
param($message)
Write-Host $message
}
function Write-OctopusSuccess
{
param($message)
Write-Host $message
}
function Write-OctopusWarning
{
param($message)
Write-Warning "$message"
}
function Write-OctopusCritical
{
param ($message)
Write-Error "$message"
}
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-OctopusVerbose $body
Write-OctopusInformation "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-OctopusVerbose "Checking to see if $url is already in the cache"
if ($cachedResults.ContainsKey($url) -eq $true)
{
Write-OctopusVerbose "$url is already in the cache, returning the result"
return $cachedResults[$url]
}
}
else
{
Write-OctopusVerbose "Ignoring cache."
}
Write-OctopusVerbose "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-OctopusVerbose "Adding $url to the cache"
$cachedResults.add($url, $result)
return $result
}
catch
{
if ($null -ne $_.Exception.Response)
{
if ($_.Exception.Response.StatusCode -eq 401)
{
Write-OctopusCritical "Unauthorized error returned from $url, please verify API key and try again"
}
elseif ($_.Exception.Response.statusCode -eq 403)
{
Write-OctopusCritical "Forbidden error returned from $url, please verify API key and try again"
}
else
{
Write-OctopusVerbose -Message "Error calling $url $($_.Exception.Message) StatusCode: $($_.Exception.Response.StatusCode )"
}
}
else
{
Write-OctopusVerbose $_.Exception
}
}
Throw "There was an error calling the Octopus API please check the log for more details"
}
function Get-OctopusItemList
{
param(
$itemType,
$endpoint,
$spaceId,
$octopusUrl,
$octopusApiKey
)
if ($null -ne $spaceId)
{
Write-OctopusVerbose "Pulling back all the $itemType in $spaceId"
}
else
{
Write-OctopusVerbose "Pulling back all the $itemType for the entire instance"
}
if ($endPoint -match "\?+")
{
$endpointWithParams = "$($endPoint)&skip=0&take=10000"
}
else
{
$endpointWithParams = "$($endPoint)?skip=0&take=10000"
}
$itemList = Invoke-OctopusApi -octopusUrl $octopusUrl -endPoint $endpointWithParams -spaceId $spaceId -apiKey $octopusApiKey -method "GET"
if ($itemList -is [array])
{
Write-OctopusVerbose "Found $($itemList.Length) $itemType."
return ,$itemList
}
else
{
Write-OctopusVerbose "Found $($itemList.Items.Length) $itemType."
return ,$itemList.Items
}
}
function Get-OctopusItemByName
{
param (
$itemType,
$itemName,
$endPoint,
$spaceId,
$octopusUrl,
$octopusApiKey
)
$itemList = Get-OctopusItemList -endpoint "$($endpoint)?partialName=$([uri]::EscapeDataString($itemName))" -itemType $itemType -spaceId $spaceId -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
$filteredItem = $itemList | Where-Object { $_.Name.ToLower().Trim() -eq $itemName.ToLower().Trim() }
if ($null -eq $filteredItem)
{
Write-OctopusInformation "Unable to find the $itemType $itemName"
exit 1
}
return $filteredItem
}
function Test-OctopusObjectHasProperty
{
param(
$objectToTest,
$propertyName
)
$hasProperty = Get-Member -InputObject $objectToTest -Name $propertyName -MemberType Properties
if ($hasProperty)
{
Write-OctopusVerbose "$propertyName property found."
return $true
}
else
{
Write-OctopusVerbose "$propertyName property missing."
return $false
}
}
$space = Get-OctopusItemByName -itemType "Space" -endPoint "spaces" -itemName $spaceName -spaceId $null -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
$environmentList = Get-OctopusItemList -itemType "Environments" -endpoint "environments" -spaceId $($space.Id) -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
$projectList = Get-OctopusItemList -itemType "Projects" -endpoint "projects" -spaceId $($space.Id) -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
$deploymentTargetList = Get-OctopusItemList -itemType "DeploymentTargets" -endpoint "machines?roles=$($targetRole)" -spaceId $($space.Id) -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
$deploymentTargetsDeployments = @()
$minDate = Get-Date
$minDate = $minDate.AddDays(($daysToQuery * -1))
Write-Host "The minimum date allowed is: $minDate"
foreach ($deploymentTarget in $deploymentTargetList)
{
$taskList = Get-OctopusItemList -itemType "Deployment Target Deployments" -endpoint "machines/$($deploymentTarget.Id)/tasks" -spaceId $($space.Id) -octopusUrl $octopusUrl -octopusApiKey $octopusApiKey
foreach ($task in $taskList)
{
if ($task.QueueTime -lt $minDate)
{
break
}
if ((Test-OctopusObjectHasProperty -propertyName "DeploymentId" -objectToTest $task.Arguments) -eq $false)
{
continue
}
$deployment = Invoke-OctopusApi -octopusUrl $octopusUrl -endPoint "deployments/$($task.Arguments.DeploymentId)" -spaceId $spaceId -apiKey $octopusApiKey -method "GET"
$environment = $environmentList | Where-Object { $_.Id -eq $deployment.EnvironmentId }
$project = $projectList | Where-Object { $_.Id -eq $deployment.ProjectId }
$release = Invoke-OctopusApi -octopusUrl $octopusUrl -endPoint "releases/$($deployment.ReleaseId)" -spaceId $spaceId -apiKey $octopusApiKey -method "GET"
$deploymentTargetsDeployments += @{
DeploymentTargetName = $deploymentTarget.Name
DeploymentTargetId = $deploymentTarget.Id
DeploymentState = $task.State
Environment = $environment.Name
Project = $project.Name
ReleaseVersion = $release.Version
QueuedTime = $task.QueueTime
}
}
}
if (Test-Path $reportPath)
{
Remove-Item $reportPath
}
New-Item $reportPath -ItemType File
Add-Content -Path $reportPath -Value "Machine Name,Environment Name,Project Name,Release Version,Deployment State,Queue DateTime,Machine Id"
Foreach ($deployedToMachine in $deploymentTargetsDeployments)
{
Add-Content -Path $reportPath -Value "$($deployedToMachine.DeploymentTargetName),$($deployedToMachine.Environment),$($deployedToMachine.Project),$($deployedToMachine.ReleaseVersion),$($deployedToMachine.DeploymentState),$($deployedToMachine.QueuedTime),$($deployedToMachine.DeploymentTargetId)"
}
Help us continuously improve
Please let us know if you have any feedback about this page.
Page updated on Sunday, January 1, 2023