Skip to content

Instantly share code, notes, and snippets.

@fdcastel
Created January 2, 2026 12:19
Show Gist options
  • Select an option

  • Save fdcastel/cddf7ac8a4a614fc0a1e3b6d86e4f3da to your computer and use it in GitHub Desktop.

Select an option

Save fdcastel/cddf7ac8a4a614fc0a1e3b6d86e4f3da to your computer and use it in GitHub Desktop.
Monitors Syncthing connections in real-time with transfer rate calculations
<#
.SYNOPSIS
Monitors Syncthing connections in real-time with transfer rate calculations.
.DESCRIPTION
Runs every 5 seconds to display Syncthing connection status. The first iteration
shows current values without rate information. Subsequent iterations include
inTotalMbps showing the data transfer rate.
.PARAMETER IntervalSeconds
The interval between checks in seconds. Default is 5.
.EXAMPLE
.\Monitor-SyncthingConnections.ps1
.EXAMPLE
.\Monitor-SyncthingConnections.ps1 -IntervalSeconds 10
#>
[CmdletBinding()]
param(
[Parameter()]
[int]$IntervalSeconds = 5
)
function Resolve-HostName {
<#
.SYNOPSIS
Resolves an IP address or hostname to its DNS name.
.DESCRIPTION
Cross-platform function to resolve hostnames. Uses Resolve-DnsName on Windows
and host/dig commands on Linux.
.PARAMETER Address
The IP address or hostname to resolve
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Address
)
try {
if ($IsLinux -or $IsMacOS) {
# Try using 'host' command on Linux/Mac
$hostOutput = host $Address 2>$null
if ($LASTEXITCODE -eq 0 -and $hostOutput) {
# Parse output like "1.2.3.4.in-addr.arpa domain name pointer hostname.example.com."
if ($hostOutput -match 'domain name pointer\s+(.+)\.$') {
return $matches[1]
} elseif ($hostOutput -match 'has address') {
# Forward lookup, return original
return $Address
}
}
# Fallback: try 'dig' if available
$digOutput = dig +short -x $Address 2>$null
if ($LASTEXITCODE -eq 0 -and $digOutput) {
$hostname = ($digOutput | Select-Object -First 1).TrimEnd('.')
if ($hostname) {
return $hostname
}
}
# If all fails, return the address
return $Address
} else {
# Windows: use Resolve-DnsName
$dnsResult = Resolve-DnsName -Name $Address -ErrorAction SilentlyContinue
if ($dnsResult) {
return $dnsResult | Select-Object -ExpandProperty 'NameHost' -First 1
} else {
return $Address
}
}
} catch {
return $Address
}
}
function Add-ConnectionRate {
<#
.SYNOPSIS
Calculates the data transfer rate between two Syncthing connection snapshots.
.DESCRIPTION
Takes two connection snapshots (Prior and Current) and calculates the inTotalMbps
(MB per second) for each connection based on the difference in transferred data
and time elapsed.
.PARAMETER Prior
The previous connection snapshot
.PARAMETER Current
The current connection snapshot
.EXAMPLE
$rate = Add-ConnectionRate -Prior $previousData -Current $currentData
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[PSCustomObject[]]$Prior,
[Parameter(Mandatory = $true)]
[PSCustomObject[]]$Current
)
$result = @()
for ($i = 0; $i -lt $Current.Count; $i++) {
$currentItem = $Current[$i]
# Try to find matching prior item by index (since host might be empty)
# In a more robust solution, you'd match by device ID or address
if ($i -lt $Prior.Count) {
$priorItem = $Prior[$i]
# Calculate time difference in seconds
$currentTime = [DateTime]::Parse($currentItem.at)
$priorTime = [DateTime]::Parse($priorItem.at)
$timeDiffSeconds = ($currentTime - $priorTime).TotalSeconds
# Calculate MB difference
$mbDiff = $currentItem.inTotalMb - $priorItem.inTotalMb
# Calculate rate (MB per second)
if ($timeDiffSeconds -gt 0) {
$mbps = [math]::Round($mbDiff / $timeDiffSeconds, 3)
} else {
$mbps = 0
}
# Add the rate and diff properties to current item
$currentItem | Add-Member -NotePropertyName 'inTotalMbDiff' -NotePropertyValue $mbDiff -Force
$currentItem | Add-Member -NotePropertyName 'inTotalMbps' -NotePropertyValue $mbps -Force
}
$result += $currentItem
}
return $result
}
# Main monitoring loop
$priorData = $null
while ($true) {
Clear-Host
# Get current connection data
$connections = syncthing cli show connections |
ConvertFrom-Json |
Select-Object -ExpandProperty 'Connections'
$currentData = $connections.psobject.Properties.Value |
Select-Object @{Name='host'; Expression={Resolve-HostName -Address $_.address.split(":")[0]}},
'connected',
'paused',
'startedAt',
'at',
@{Name='inTotalMb'; Expression={[int]($_.inBytesTotal / 1MB)}} |
Sort-Object 'host'
if ($priorData -eq $null) {
# First iteration - display without rate
$currentData | Format-Table -AutoSize
} else {
# Subsequent iterations - calculate and display rate
$dataWithRate = Add-ConnectionRate -Prior $priorData -Current $currentData
$dataWithRate | Format-Table -AutoSize
}
# Store current data for next iteration
$priorData = $currentData
# Wait for the specified interval
Start-Sleep -Seconds $IntervalSeconds
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment