List all Proxmox VE guests with status and locks (pvesh + jq)
A Bash script that lists every VM and container in the cluster with node, status, lock, memory and uptime, using the Proxmox VE API through pvesh. Filters for running or locked guests.
Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?
What this changes
Read-only: it reads the guest list with pvesh get /cluster/resources and prints a table or JSON; no VM, container or setting is changed.
How to undo it
Nothing to undo.
qm list and pct list only show guests on the current node. The API endpoint /cluster/resources returns every guest in the cluster in one call, including fields such as node, status, lock, maxmem, uptime and template. This script reads it with pvesh and formats it as a table.
Requirements
- Run on any node of the cluster, as root or a user allowed to use
pvesh. The API only returns guests you have permission to see. jqfor JSON parsing. It may not be installed by default:apt install jq.
Script
#!/usr/bin/env bash
# pve-guests.sh - list every VM and container in a Proxmox VE cluster
# License: CC0-1.0
# Usage: pve-guests.sh [-r] [-l] [-j]
# -r only running guests
# -l only guests that currently hold a config lock
# -j print raw JSON instead of a table
set -euo pipefail
only_running=0
only_locked=0
raw_json=0
while getopts ":rlj" opt; do
case "$opt" in
r) only_running=1 ;;
l) only_locked=1 ;;
j) raw_json=1 ;;
*) echo "Usage: $0 [-r] [-l] [-j]" >&2; exit 2 ;;
esac
done
for cmd in pvesh jq; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: '$cmd' not found. Run this on a Proxmox VE node (install jq with: apt install jq)." >&2
exit 1
fi
done
json=$(pvesh get /cluster/resources --type vm --output-format json)
filtered=$(jq --argjson running "$only_running" --argjson locked "$only_locked" '
[ .[]
| select($running == 0 or .status == "running")
| select($locked == 0 or ((.lock // "") != ""))
] | sort_by(.vmid)
' <<<"$json")
if [ "$raw_json" -eq 1 ]; then
printf '%s\n' "$filtered"
exit 0
fi
count=$(jq 'length' <<<"$filtered")
if [ "$count" -eq 0 ]; then
echo "No matching guests."
exit 0
fi
printf '%-8s %-5s %-12s %-9s %-10s %8s %10s %s\n' VMID TYPE NODE STATUS LOCK MEM_MIB UPTIME NAME
jq -r '
.[] | [
(.vmid | tostring),
.type,
.node,
.status,
(if (.lock // "") == "" then "-" else .lock end),
((.maxmem // 0) / 1048576 | floor | tostring),
((.uptime // 0) as $u
| if $u == 0 then "-"
else "\($u / 86400 | floor)d\(($u % 86400) / 3600 | floor)h" end),
((.name // "") + (if (.template // 0) == 1 then " (template)" else "" end))
] | @tsv
' <<<"$filtered" |
while IFS=$'\t' read -r vmid type node status lock mem uptime name; do
printf '%-8s %-5s %-12s %-9s %-10s %8s %10s %s\n' \
"$vmid" "$type" "$node" "$status" "$lock" "$mem" "$uptime" "$name"
done
echo
jq -r '"\(length) guests: \([.[] | select(.status == "running")] | length) running, \([.[] | select((.lock // "") != "")] | length) locked"' <<<"$filtered"
Usage
chmod +x pve-guests.sh
./pve-guests.sh # all guests
./pve-guests.sh -r # running only
./pve-guests.sh -l # guests with a config lock (backup, migrate, snapshot...)
./pve-guests.sh -j | jq '.[] | select(.node == "pve1") | .vmid'
Example output:
VMID TYPE NODE STATUS LOCK MEM_MIB UPTIME NAME
100 lxc pve2 stopped backup 512 - dns
101 qemu pve1 running - 2048 1d2h web1
9000 qemu pve1 stopped - 2048 - ubuntu-tpl (template)
3 guests: 1 running, 1 locked
The -l view is handy after an interrupted backup or migration: a lock that stays after its task has finished points to the guests you may need to check (see the entry on VM is locked (backup)).
Official documentation
Did this work for you?
No votes yet. Be the first.
If it did not work, the report form below tells the editors what went wrong.
See also
- 0058 Safe bash script template with set ‑euo pipefail and trap A starting point for bash scripts that stops on errors, rejects unset variables, cleans up temp files on exit and parses options.… Intermediate · Cheat sheet · Linux, macOS Script Shell scripting 15 Oct 2026
- 0059 Incremental snapshot backups with rsync A bash script that copies a folder into dated snapshots with rsync, hard-links unchanged files to the previous snapshot to save space,… Advanced · Step by step · Linux, macOS Script Backups & syncing · Shell scripting 15 Oct 2026
- 0061 Fix: Address already in use (free a busy port) Your server cannot start because another process already listens on its port. This script shows which process holds the port and stops… Intermediate · Fixes an error · Linux, macOS Script Processes & ports · Shell scripting 15 Oct 2026
- 0100 Create a VM and a cloud-init template with qm Create KVM virtual machines from the command line with qm, then build a reusable cloud-init template from a cloud image and clone… Intermediate · Step by step · Linux Article Basics · VMs & containers 15 Oct 2026
- 0101 Create LXC containers with pct and pveam Download a container template with pveam, create an unprivileged LXC container with pct, give it a network address and get a shell… Beginner · Step by step · Linux Article VMs & containers 15 Oct 2026
- 0104 Build a Proxmox VE cluster with pvecm and live-migrate VMs Join Proxmox VE nodes into a cluster with pvecm create and pvecm add, check quorum with pvecm status, then move running VMs… Advanced · Step by step · Linux Article Clusters & high availability · VMs & containers 15 Oct 2026
Repos in the wild
- proxmox/qemu-server: the Proxmox VE virtual machine manager proxmox/qemu-server Read-only GitHub mirror of qemu-server, the Proxmox VE package that manages QEMU/KVM virtual machines and provides the qm and qmrestore commands. GitHub
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Dominik +4,083 chars