PRTG-API-Automation: Mit Python die Sanierung beschleunigen
Die PRTG-API wird von vielen Admins unterschätzt. Dabei ist sie überraschend mächtig. Mit 20 bis 50 Zeilen Python lassen sich typische Sanierungs-Aufgaben automatisieren, die manuell Stunden dauern: verwaiste Sensoren finden, Tag-Chaos aufspüren, pausierte Leichen auflisten. Der Einstieg ist einfacher als viele denken.
Für IT-Entscheider im Mittelstand ist die API aus 3 Gründen interessant. Erstens spart sie Lizenzkosten: wer 200-500 tote oder duplizierte Sensoren per Script identifiziert und löscht, fällt oft in die nächst-niedrigere Lizenzstufe zurück. Zweitens skaliert sie die Admin-Kapazität: ein einmal geschriebenes Python-Script prüft in 30 Sekunden, wofür ein Admin manuell einen halben Tag brauchen würde. Drittens macht sie Audits wiederholbar: ein quartalsweiser Health-Check lässt sich als Cron-Job aufsetzen, statt jedes Mal neu durch Menüs zu klicken. Die folgenden Beispiele zeigen konkrete Use-Cases aus echten Sanierungsprojekten.
Warum die PRTG-API die unterschätzte Hälfte von PRTG ist
PRTG hat eine HTTP-basierte API, die seit vielen Versionen existiert und stabil läuft. Kein REST im modernen Sinn, eher ein Web-Endpoint mit GET-Parametern. Für Scripting-Zwecke funktioniert das genauso gut. Mit einem einzigen HTTP-Request kannst du:
- Alle Sensoren, Devices oder Gruppen abfragen
- Sensoren pausieren, fortsetzen, löschen
- Namen, Tags, Properties ändern
- Sensor-Messwerte auslesen
- Objekte duplizieren
Du brauchst keine SDK-Installation, keine Library, keinen API-Client. Python mit requests reicht, dazu einen API-Passhash, den du im PRTG-Interface unter „My Account" erzeugst.
Der Passhash ist ein Credential-Ersatz, mit dem du Scripts authentifizieren kannst, ohne das Klartext-Passwort im Code zu haben. Nie im Git committen.
Der einfachste Start: Sensoren auflisten
Der erste nützliche Baustein ist eine Abfrage aller Sensoren. Dafür gibt es den Endpoint /api/table.xml mit content=sensors und den gewünschten Spalten:
import requests
import xml.etree.ElementTree as ET
PRTG_HOST = "http://prtg.example.com"
USER = "prtgadmin"
PASSHASH = "1234567890" # in PRTG erzeugen: My Account -> Passhash (aeltere Versionen) oder API Token (ab PRTG 23.x)
def list_sensors():
r = requests.get(f"{PRTG_HOST}/api/table.xml", params={
"content": "sensors",
"columns": "objid,device,group,sensor,status,tags",
"count": "50000", # groß genug für alle Sensoren; PRTG gibt nur vorhandene zurück
"output": "xml",
"username": USER,
"passhash": PASSHASH,
}, timeout=30)
r.raise_for_status()
root = ET.fromstring(r.text)
for item in root.findall(".//item"):
obj = {c.tag: (c.text or "") for c in item}
print(f"#{obj['objid']:>6} | {obj['device']:30.30} | {obj['sensor']}")
list_sensors()
Das sind 20 Zeilen und du hast eine vollständige Sensor-Liste mit IDs, Geräten und Status. Sofort filterbar, sofort in Python weiterverarbeitbar. Du brauchst dich nicht durch die PRTG-UI zu klicken, um 800 Sensoren zu sichten.
Praxis-Fall 1: Pausierte Sensoren mit leerer Begründung finden
Einer der häufigsten Audit-Befunde: pausierte Sensoren, bei denen niemand mehr weiß, warum sie pausiert wurden. Besonders gefährlich: solche ohne Begründung. Die findest du so:
# Erweitere die Spalten um message_raw (Pause-Grund)
def find_empty_paused():
r = requests.get(f"{PRTG_HOST}/api/table.xml", params={
"content": "sensors",
"columns": "objid,device,sensor,status,message_raw",
"filter_status": "7", # 7 = paused durch User
"count": "50000", # groß genug für alle Sensoren; PRTG gibt nur vorhandene zurück
"output": "xml",
"username": USER,
"passhash": PASSHASH,
}, timeout=30)
root = ET.fromstring(r.text)
leichen = []
for item in root.findall(".//item"):
obj = {c.tag: (c.text or "") for c in item}
msg = obj.get("message_raw", "").strip()
if not msg or msg.lower() in ("tbd", "check", "?"):
leichen.append(obj)
return leichen
for s in find_empty_paused():
print(f" LEICHE: {s['device']} / {s['sensor']} (#{s['objid']})")
Ergebnis: Eine saubere Liste aller pausierten Sensoren mit leerer oder nichtssagender Begründung. In einer 2.000-Sensoren-Umgebung liefert das Script in Sekunden dutzende Kandidaten, die ein menschliches Urteil brauchen. Die Stunden Klickarbeit im UI sparst du dir.
Praxis-Fall 2: Tag-Chaos auswerten
Im vorherigen Artikel habe ich über Tag-Widersprüche geschrieben (keep + delete_me auf demselben Sensor). Mit der API kannst du das maschinell aufspüren:
from collections import Counter
CONFLICT_PAIRS = [
({"wichtig", "obsolete"}, "wichtig + obsolete"),
({"keep", "delete_me"}, "keep + delete_me"),
({"v1", "v2"}, "mehrere Versionen"),
({"neu", "alt", "old"}, "neu + alt gleichzeitig"),
]
def scan_tag_conflicts():
r = requests.get(f"{PRTG_HOST}/api/table.xml", params={
"content": "sensors",
"columns": "objid,device,sensor,tags",
"count": "50000",
"output": "xml",
"username": USER,
"passhash": PASSHASH,
}, timeout=30)
root = ET.fromstring(r.text)
all_tags = Counter()
conflicts = []
for item in root.findall(".//item"):
obj = {c.tag: (c.text or "") for c in item}
tags = set((obj.get("tags") or "").lower().split())
all_tags.update(tags)
for conflict_set, label in CONFLICT_PAIRS:
if len(conflict_set.intersection(tags)) >= 2:
conflicts.append((obj["device"], obj["sensor"], label))
print(f"Tag-Inventur: {len(all_tags)} eindeutige Tags im System")
print("Seltenste (mögliche Tippfehler):")
for tag, n in all_tags.most_common()[-10:]:
print(f" {tag!r}: {n}x")
print(f"\nKonflikte gefunden: {len(conflicts)}")
for dev, sens, label in conflicts[:20]:
print(f" {dev} / {sens}: {label}")
scan_tag_conflicts()
2 Dinge fallen dabei sofort auf:
- Die seltensten Tags sind fast immer Tippfehler,
wichitgstattwichtig,depricatedstattdeprecated. Die Liste der 10 seltensten Tags ist eine fast perfekte Tippfehler-Detektion. - Die Konflikt-Sensoren sind die Sensoren, die einen menschlichen Entscheid brauchen: wenn auf einem Sensor
wichtigundobsoletegleichzeitig stehen, muss jemand sich festlegen.
Praxis-Fall 3: Namens-Präfix-Analyse
Die Namens-Archäologie, welche Präfixe welchen Epochen angehören, lässt sich ebenfalls in wenigen Zeilen aufbereiten:
import re
from collections import Counter
def analyze_prefixes():
r = requests.get(f"{PRTG_HOST}/api/table.xml", params={
"content": "sensors",
"columns": "objid,sensor",
"count": "50000",
"output": "xml",
"username": USER,
"passhash": PASSHASH,
}, timeout=30)
root = ET.fromstring(r.text)
prefix_counter = Counter()
suspect_prefixes = ("DEPRECATED_", "old_", "temp_", "test_",
"MIGRATE_", "TBD_", "delete_", "ALT_")
suspects = []
for item in root.findall(".//item"):
name = (item.find("sensor").text or "")
# Erste 3-4 Zeichen als Präfix-Indikator
m = re.match(r"^([A-Za-z_]{2,10})[\s_-]", name)
if m:
prefix_counter[m.group(1)] += 1
for p in suspect_prefixes:
if name.startswith(p):
suspects.append(name)
break
print("Häufige Präfixe:")
for pfx, n in prefix_counter.most_common(15):
print(f" {pfx:20.20} {n:>4}x")
print(f"\nSensoren mit Legacy-Präfix: {len(suspects)}")
analyze_prefixes()
Das Ergebnis ist eine Tabelle, in der du auf einen Blick siehst: "Wir haben 87 Sensoren mit CPU-Präfix, 34 mit cpu, 12 mit SYS_CPU, 5 mit old_CPU". Daraus leitet sich der Cleanup-Plan direkt ab.
Wenn du die Scripts nicht selbst schreiben willst
Diese Analysen laufen in meinem PRTG-Audit-Paket automatisiert ab. Du bekommst die Ergebnisse als priorisierten Findings-Katalog plus Sofort-Sanierung, ohne dass du Python lernen musst.
Aktiv aufräumen: Umbenennen und entpausen
Bis jetzt haben wir nur gelesen. Aber die PRTG-API erlaubt auch das Schreiben. Mit /api/setobjectproperty.htm kannst du einen Sensor umbenennen, Tags ändern und vieles mehr:
def rename_sensor(objid, new_name):
requests.get(f"{PRTG_HOST}/api/setobjectproperty.htm", params={
"id": objid,
"name": "name",
"value": new_name,
"username": USER,
"passhash": PASSHASH,
}, timeout=30).raise_for_status()
def unpause(objid):
requests.get(f"{PRTG_HOST}/api/pause.htm", params={
"id": objid,
"action": "1", # 1 = resume
"username": USER,
"passhash": PASSHASH,
}, timeout=30).raise_for_status()
# Alle Sensoren mit DEPRECATED_-Praefix nach Review entfernen:
# (VORSICHT - erst auf Testumgebung probieren!)
# for s in find_deprecated_sensors():
# delete_sensor(s["objid"])
Wichtig: Bulk-Operationen gegen die produktive PRTG nie ohne vorherigen Test auf einer Kopie. Nichts ist peinlicher, als versehentlich 400 echte Sensoren zu löschen. Für Tests kannst du dir schnell eine PRTG-Free-Instanz in einer Windows-VM aufsetzen und gegen diese erst üben.
Der nächste Schritt: Aus Scripten wird ein Toolkit
Die ersten 2, 3 Scripts sind spontan geschrieben. Nach dem 4. oder 5. merkt man: Es gibt ein paar wiederkehrende Patterns, die sich bündeln lassen. Eine kleine Klasse für die API-Aufrufe, ein Format für die Ausgabe, eine Option für CSV-Export. Plötzlich hat man ein internes Toolkit, das bei jeder neuen PRTG-Umgebung ausgepackt werden kann.
So habe ich den Analyse-Prozess entwickelt, den ich heute im Audit-Paket einsetze: erst die manuellen Klicks, dann kleine Scripts, dann ein strukturiertes Python-Package. Heute dauert eine Bestandsaufnahme, die früher einen halben Tag Klickarbeit war, noch rund 30 Minuten. Und der Output ist detaillierter als jede manuelle Analyse.
Wo die API-Dokumentation liegt
Ein oft übersehener Trick: Die komplette PRTG-API-Dokumentation ist in deiner eigenen PRTG-Installation eingebaut, unter http://DEIN-PRTG/api.htm. Da findest du alle verfügbaren Endpoints, ihre Parameter und Rückgabe-Formate. Das ist oft aktueller als die Online-Dokumentation bei Paessler, weil sie zur exakten Version passt, die du einsetzt.
Wer jetzt Lust bekommen hat, selbst zu experimentieren: Setze dir in einer Windows-VM eine PRTG-Free-Instanz auf (kostenlos bis 100 Sensoren) und probiere die Scripts in einer sicheren Umgebung durch. Danach hast du die Grundlage, um auch in deiner produktiven Installation gezielt zu automatisieren.