Skip to content
Commitpedia
Log in Join & edit

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?

Edit history of List all Proxmox VE guests with status and locks (pvesh + jq): 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

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.
  • jq for 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

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +4,083 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?