Generating a report of active systems¶
Managing a fleet of enrolled systems across multiple customer tenants means you need visibility into what's deployed, what's online, and what might need attention. This script queries the Enclave API to produce a complete inventory of systems enrolled in a given organisation, showing connection state, platform type, software version, and when each system was last seen. It can also flag duplicate virtual IP addresses that may need resolving.
You can display results as a formatted table in the terminal or export them to CSV for further analysis - useful for client reporting, audit preparation, or identifying systems running outdated versions of Enclave.
Prerequisites¶
- An Enclave API key
- Your Organisation ID
- PowerShell 5.1 or later
How it works¶
The script pages through the GET /org/{orgId}/systems endpoint, collecting every enrolled system in the organisation. It sorts systems by their last-seen date so you can quickly spot which ones have been offline the longest.
After listing all systems, the script checks for duplicate virtual IP addresses. If any are found, it prints a warning with the affected system identifiers and a suggested remediation command.
When exporting to CSV, additional fields (system tags and full OS version) are included that aren't shown in the terminal table view.
The script¶
Save the following script as a .ps1 file.
-orgId, the organisation to run queries against.-apiKey, the Enclave API key. Set theENCLAVE_API_KEYenvironment variable as an alternative.-csvPath, an optional file path. When provided, results are exported to CSV instead of displayed in the terminal.
Param(
[Parameter(Mandatory=$false)]
[string]$orgId,
[Parameter(Mandatory=$false)]
[string]$apiKey,
[Parameter(Mandatory=$false)]
[string]$csvPath
)
$ErrorActionPreference = "Stop"
if (-not $apiKey) {
$apiKey = if ($env:ENCLAVE_API_KEY) {
$env:ENCLAVE_API_KEY
} else {
Read-Host "Please enter your Enclave Personal Access Token"
}
}
if (-not $apiKey) {
Write-Error "No API key provided; either specify the '-apiKey' argument, or set the ENCLAVE_API_KEY environment variable."
return;
}
if (-not $orgId) {
$orgId = Read-Host "Please enter your Enclave Organisation Id"
}
function Get-HumanReadableTimeDifference {
param ([datetime]$pastTime)
$timeDifference = [datetime]::Now - $pastTime
if ($timeDifference.TotalDays -ge 2) {
return "{0} days ago" -f [math]::Floor($timeDifference.TotalDays)
} elseif ($timeDifference.TotalHours -ge 2) {
return "{0} hours ago" -f [math]::Floor($timeDifference.TotalHours)
} elseif ($timeDifference.TotalMinutes -ge 2) {
return "{0} minutes ago" -f [math]::Floor($timeDifference.TotalMinutes)
} else {
return "{0} seconds ago" -f [math]::Floor($timeDifference.TotalSeconds)
}
}
function Format-DateTime {
param (
[datetime]$dateTime
)
return Get-Date $dateTime -Format "dd MMMM yyyy"
}
$headers = @{Authorization = "Bearer $apiKey"}
$contentType = "application/json"
$uri = "https://api.enclave.io/org/$orgId/systems"
$systems = @()
do {
$response = Invoke-RestMethod -ContentType $contentType -Method Get -Uri $uri -Headers $headers
$systems += $response.items | Select-Object systemId, state, lastSeen, enrolledAt, enclaveVersion, hostname, platformType, description, virtualAddress, osVersion, tags
$uri = if ($null -ne $response.links.next -and $response.links.next -ne "") { $response.links.next } else { $null }
} while ($uri)
# Sort systems by lastSeen date for the initial output
$systems = $systems | Sort-Object lastSeen
foreach ($system in $systems) {
$system.lastSeen = if ($system.lastSeen) { Get-HumanReadableTimeDifference -pastTime $system.lastSeen } else { "Never seen" }
$system.enrolledAt = Format-DateTime -dateTime $system.enrolledAt
# Clean up osVersion - remove line breaks and extra whitespace
if ($system.osVersion) {
$system.osVersion = ($system.osVersion -split '\s+') -join ' '
}
# Format tags as a comma-separated string
if ($system.tags -and $system.tags.Count -gt 0) {
try {
$system.tags = ($system.tags | ForEach-Object { if ($_.tag) { $_.tag } }) -join ", "
} catch {
$system.tags = ""
}
} else {
$system.tags = ""
}
}
# Display or export the systems data
if ($csvPath) {
$systems | Export-Csv -Path $csvPath -NoTypeInformation
Write-Output "Data exported to: $csvPath"
} else {
$systems | Format-Table -Property systemId, virtualAddress, state, platformType, lastSeen, enclaveVersion, hostname, enrolledAt, description -AutoSize
}
# Count of total systems
Write-Output "System count: $($systems.Count)`n"
# Find duplicates based on virtualAddress
$duplicateVirtualAddresses = $systems | Group-Object -Property virtualAddress | Where-Object { $_.Count -gt 1 }
if ($duplicateVirtualAddresses)
{
# Extract the list of duplicate virtual addresses
$duplicateVirtualAddressesList = $duplicateVirtualAddresses | Select-Object -ExpandProperty Name
# Filter systems that have duplicate virtualAddress
$duplicateSystems = $systems | Where-Object { $duplicateVirtualAddressesList -contains $_.virtualAddress }
Write-Host "Warning: Duplicate virtual addresses detected between the following systems:" -ForegroundColor Yellow
# Sort by virtualAddress and display only systemId and virtualAddress
$duplicateSystems | Sort-Object virtualAddress | Format-Table -Property systemId, virtualAddress, state, hostname -AutoSize
Write-Host "Consider using the set-config command to resolve the duplicate IP address conflict on affected systems.`n" -ForegroundColor Yellow
Write-Host " C:\> enclave set-config virtual-ip x.x.x.x`n"
Write-Host "For more information, please refer to https://docs.enclave.io/agent/config/#virtual-ip`n" -ForegroundColor Yellow
}
Usage¶
Run the script interactively (you'll be prompted for credentials):
.\active-systems-report.ps1
Pass parameters directly and export to CSV:
.\active-systems-report.ps1 -orgId "b87f2e1a3d9f" -apiKey $env:ENCLAVE_API_KEY -csvPath "trantor-systems.csv"
Scheduling¶
This script is typically run ad hoc when you need a snapshot of enrolled systems for a specific tenant. If you want to track inventory over time, you can schedule the CSV export to run on a recurring basis using Windows Task Scheduler, your RMM platform, or Azure Functions, and archive the output to a shared location for trend analysis.