Adapter für Assetexport und Veeam

Handbuch · API und Verfügbarkeit · Datenquellen einrichten · Ingest-Referenz

Die hier beschriebenen Push-Adapter gehören zur Erweiterung nach v1.25.0. Auf einer Instanz mit dieser Erweiterung unter Einstellungen > API-Zugänge das Adapter-Paket herunterladen (/settings/api-keys/adapters.zip). Enthalten sind push.mjs, asset-export.mjs, Export-VeeamSessions.ps1 und Anleitungen auf Deutsch und Englisch. Vor dem ersten Versand Quelle, Schlüssel und Zuordnungen einrichten.

Welches Werkzeug wofür?

Werkzeug Aufgabe und Grenze
Windows Inventory Collector Erfasst den einzelnen Rechner, auf dem er gestartet wird, ergänzt Angaben über ein lokales Formular und schreibt Inventory-JSON. Keine Netzwerk-Discovery und kein regelmäßiger Push-Dienst.
asset-export.mjs Wandelt einen normalisierten Assetexport in einen Ingest-Batch um. Fragt Checkmk, Jamf oder andere Hersteller nicht selbst ab.
Export-VeeamSessions.ps1 Liest abgeschlossene VM-Backup-Sitzungen über Get-VBRBackupSession und erzeugt einen Delta-Batch.
push.mjs Sendet einen gespeicherten Batch per HTTPS mit Adapter-Schlüssel und schreibt eine Quittung.

Windows Inventory Collector

Der Collector ist unter Assets > Rechner inventarisieren und Einstellungen > API-Zugänge erhältlich. Auf dem Zielrechner ausführen. Er liest Betriebssystem, Hardware, Netzwerk, installierte Software, Dienste, offene Ports und Sicherheitsstatus. Ohne erhöhte Rechte bleiben beispielsweise BitLocker- und Secure-Boot-Angaben unvollständig.

Das Skript überträgt keine Daten an ISMS Lite. Seine JSON-Datei dient der geführten Asset-Anlage über einen API-/MCP-Client. Die Struktur ist nicht dieselbe wie der normalisierte Mehrgeräteexport für asset-export.mjs. Für laufende Synchronisation aus einem vorhandenen Inventarsystem den folgenden Ablauf verwenden.

Normalisierten Assetexport vorbereiten

Auf dem Adapter-Rechner wird Node.js 22 oder neuer benötigt; für die beiden .mjs-Beispiele sind keine zusätzlichen npm-Pakete erforderlich. Eine kundenseitige Abfrage liest den vereinbarten Bestand aus dem Quellsystem und schreibt beispielsweise export.json:

{
  "observedAt": "2026-09-19T08:00:00Z",
  "coverage": "site-a-managed-assets",
  "complete": true,
  "assets": [
    {
      "externalId": "device-123",
      "name": "srv-01",
      "location": "Standort A",
      "ip_address": "10.0.0.10",
      "os_platform": "Linux"
    }
  ]
}

observedAt durch den tatsächlichen Erhebungszeitpunkt ersetzen. externalId muss bei Umbenennung oder IP-Wechsel gleich bleiben. coverage muss exakt zur eingerichteten Quelle passen. complete: true ergibt einen Vollabgleich; erst nach vollständigem erfolgreichen Abruf aller Seiten setzen. Mit false entsteht ein Delta-Batch.

node ./asset-export.mjs export.json pending.json 1

Die letzte Zahl ist die aktuelle Quellenrevision. Der Generator erzeugt eine Batch-ID und überschreibt keine vorhandene Ausgabedatei. Er überträgt die technischen Assetfelder, keine fachlichen Entscheidungen über Eigentümer, Kritikalität oder RPO. Seine Assetlieferungen enthalten keine Compliance-Beobachtungen; diese muss ein eigener Adapter nach dem Ingest-Vertrag ergänzen.

Batch versenden

$env:ISMS_URL = 'https://isms.example.org'
$env:ISMS_SOURCE_ID = 'UUID-DER-QUELLE'
# ISMS_API_KEY stammt aus der geschützten Umgebung des Tasks.
node ./push.mjs pending.json

ISMS_URL muss den HTTPS-Origin der Instanz ohne API-Pfad, Benutzerinformationen oder Query enthalten. Der Sender folgt keinen Weiterleitungen. Bei Erfolg entsteht pending.json.receipt.json mit der Serverantwort. Erst danach die Eingabedatei archivieren und einen neuen Batch erzeugen.

Bei einer verlorenen Antwort dieselbe Datei erneut senden. Nicht jedes Mal Export und Batch-ID neu erzeugen: Nur die Wiederholung derselben ID mit demselben Inhalt ist wiederholbar. Der Sender versucht bei Transportfehlern, 429 und Serverfehlern höchstens fünfmal zu senden, mit Wartezeit und 30 Sekunden Zeitlimit pro Versuch. Andere Fehler müssen behoben werden. Die Fehlerreferenz erklärt typische Konflikte.

JSON-Dateien und Quittungen enthalten Betriebsdaten. Zugriff auf den Task-Benutzer beschränken, Schlüssel nicht in Dateien eintragen, überlappende Tasks verhindern und erledigte Dateien nach der festgelegten lokalen Aufbewahrungsfrist entfernen. Die entfernte Nachweishistorie bleibt davon unberührt.

Veeam-Sitzungen exportieren

Das Skript setzt PowerShell 5.1 oder neuer und die zur Veeam-Installation passende PowerShell-Umgebung voraus.

Das Beispiel verwendet Get-VBRBackupSession in einer bereits authentifizierten Veeam-PowerShell-Sitzung im Kundennetz. Die Veeam-Cmdlet-Referenz beschreibt VM-Backup-Sitzungen. Die verwendete Veeam-Produktvariante, Version, Cmdlet-Verfügbarkeit, Rechte und Rückgabefelder vor Einsatz prüfen. Das mit Testdaten geprüfte Beispiel ist keine zugesagte Kompatibilität mit jeder Veeam-Installation. Andere Workloads und Veeam für Microsoft 365 benötigen eigene Zuordnungen.

  1. Eine Quelle mit objectKind: "backup_job" und createAssets: null einrichten.
  2. ISMS-Backup-Aufträge anlegen und deren IDs mit den stabilen Veeam-Job-IDs verbinden; managedFields: [] verwenden.
  3. Für Fehlerauswertung in der Quelle rules.backupFailures festlegen, beispielsweise 2 für zwei aufeinanderfolgende Fehler.
  4. Mit einem lesenden Veeam-Zugang exportieren. Im Beispiel Job-ID, Coverage und Revision ersetzen.
./Export-VeeamSessions.ps1 -JobIds 'UUID-DES-VEEAM-JOBS' `
    -Coverage 'veeam-vm-jobs' -SourceRevision 1 -OutputPath pending.json
node ./push.mjs pending.json

Vor dem Versand die Umgebungsvariablen wie oben setzen. Export und Versand können auf unterschiedlichen Rechnern laufen; dann benötigt der Veeam-Rechner kein Node.js. Die Datei geschützt zum Versand-Rechner übertragen.

Veeam-Daten Ingest-Bedeutung
Nur Sitzung mit State: Stopped Abgeschlossene Sitzung wird berücksichtigt
Result: Success backup_run mit passed
Result: Failed backup_run mit failed
Warnung oder anderes Ergebnis unknown
Sitzungs-ID Stabile Ereignis-ID
Sitzungsende Erhebungszeitpunkt des Ergebnisses

Standardmäßig liest das Beispiel sieben Tage überlappend (LookbackHours: 168); ein Ergebnis gilt bis 48 Stunden nach Sitzungsende (ValidHours: 48). Diese Werte passend zur Backup-Frequenz wählen. Bereits gelieferte Ereignisse dürfen nicht durch geänderte Gültigkeit unter derselben Ereignis-ID umgeschrieben werden.

Mehr als 20 Sitzungen je Job führen zu einem Fehler, nicht zu stiller Kürzung. Das Zeitfenster muss verspätete Sitzungen erfassen. Bei größeren Historien einen eigenen Adapter mit mehreren Delta-Batches verwenden. Der Veeam-Export sendet immer Delta und erkennt damit keine verschwundenen Jobs.

Vollständiges PowerShell-Beispiel

Der folgende Code entspricht Export-VeeamSessions.ps1 aus dem Adapter-Paket. Unter diesem Namen als UTF-8-Datei speichern und mit dem oben gezeigten Aufruf ausführen. Voraussetzung bleibt eine bereits authentifizierte Veeam-PowerShell-Sitzung. Der Export schreibt nur pending.json; den HTTPS-Versand übernimmt anschließend push.mjs aus demselben Paket.

#requires -Version 5.1
[CmdletBinding()]
param(
    [Parameter(Mandatory)][guid[]]$JobIds,
    [Parameter(Mandatory)][string]$Coverage,
    [Parameter(Mandatory)][ValidateRange(1, 2147483647)][int]$SourceRevision,
    [Parameter(Mandatory)][string]$OutputPath,
    [ValidateRange(1, 8760)][int]$ValidHours = 48,
    [ValidateRange(1, 8760)][int]$LookbackHours = 168,
    [string]$SessionsJson
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
if (Test-Path -LiteralPath $OutputPath) { throw 'Output exists. Deliver or resolve the pending batch before exporting again.' }
if ($JobIds.Count -gt 500) { throw 'At most 500 configured jobs are supported per source.' }
$observedAt = [DateTime]::UtcNow
if ($SessionsJson) {
    $sessions = @(Get-Content -LiteralPath $SessionsJson -Raw | ConvertFrom-Json)
} else {
    # Run inside an authenticated Veeam PowerShell session in the customer network.
    $sessions = @(Get-VBRBackupSession -ErrorAction Stop)
}
$objects = @()
foreach ($jobId in ($JobIds | Select-Object -Unique)) {
    $runs = @($sessions | Where-Object { [guid]$_.JobId -eq $jobId -and [string]$_.State -eq 'Stopped' } | Sort-Object EndTimeUTC -Descending)
    $observations = @()
    foreach ($run in $runs) {
        # EndTimeUTC is explicitly UTC, including when Veeam returns DateTimeKind.Unspecified.
        $end = [DateTime]::SpecifyKind([DateTime]$run.EndTimeUTC, [DateTimeKind]::Utc)
        if ($end -lt $observedAt.AddHours(-$LookbackHours)) { continue }
        if ($end -gt $observedAt) { throw 'Session timestamp is in the future.' }
        $result = switch ([string]$run.Result) { 'Success' { 'passed' } 'Failed' { 'failed' } default { 'unknown' } }
        $sessionId = ([guid]$run.Id).ToString()
        $observations += @{
            eventId = $sessionId; checkType = 'backup_run'; result = $result
            observedAt = $end.ToString('o'); validUntil = $end.AddHours($ValidHours).ToString('o')
            evidence = @{ summary = "Veeam session=$sessionId; result=$($run.Result)" }
        }
    }
    # Never truncate history silently: split a large export into explicit delta batches.
    if ($observations.Count -gt 20) { throw 'More than 20 sessions per job. Use a shorter overlap window or implement delta paging.' }
    $objects += @{ externalId = $jobId.ToString(); observations = @($observations) }
}
if (($objects | ForEach-Object { $_.observations.Count } | Measure-Object -Sum).Sum -gt 1000) { throw 'More than 1000 observations. Split into delta batches.' }
$payload = @{
    schemaVersion = 1; batchId = [guid]::NewGuid().ToString(); sourceRevision = $SourceRevision
    coverage = $Coverage; mode = 'delta'; observedAt = $observedAt.ToString('o')
    totalObjects = $objects.Count; objects = @($objects)
} | ConvertTo-Json -Depth 8
if ([Text.Encoding]::UTF8.GetByteCount($payload) -gt 1MB) { throw 'Batch exceeds 1 MiB.' }
$stream = [IO.File]::Open([IO.Path]::GetFullPath($OutputPath), [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
try {
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes($payload)
    $stream.Write($bytes, 0, $bytes.Length)
} finally { $stream.Dispose() }

SessionsJson dient ausschließlich dem Offline-Test mit zuvor erstellten Testdaten. Im echten Veeam-Betrieb diesen Parameter weglassen, damit Get-VBRBackupSession verwendet wird.

RPO und SureBackup gesondert zuordnen

Ein erfolgreicher Job beweist weder einen verwendbaren Restore-Punkt noch einen erfolgreichen Wiederherstellungstest.

  • RPO: Eine Assetquelle benötigt backup_point mit passed, dem tatsächlich gemeldeten verwendbaren restorePointAt und einer begründeten Gültigkeit. Das RPO wird am ISMS-Asset fachlich festgelegt. Eine Jobquelle allein liefert diese Assetbewertung nicht.
  • Restore/SureBackup: Einen tatsächlichen Testbericht als restore_test mit Ergebnis und Gültigkeit liefern. Fehlende oder abgelaufene Nachweise bleiben unknown.
  • Fachliche Läufe und Testabschlüsse: Dafür die Backup-Fach-API verwenden. Ingest-Beobachtungen schließen diese Abläufe nicht automatisch ab.

Diese zusätzlichen Herstellerzuordnungen müssen anhand der eingesetzten Version und tatsächlicher Daten entwickelt und im Pilot geprüft werden; sie sind nicht Bestandteil des Sitzungsbeispiels.

Weitere Hersteller und Verzeichnisse

Quelle Möglicher Adapter-Inhalt
Checkmk, Jamf Stabile Geräte-IDs und ausgewählte Assetdaten; ausdrücklich bewertete Compliance als device_compliance
Portnox Zugeordneter Gerätestatus bzw. begründete Compliance-Beobachtungen
Unimus Ergebnis und Referenz einer Konfigurationssicherung als config_backup, ohne Konfigurationsdatei oder Geheimnisse
Microsoft Entra ID / Microsoft 365 Ausgewählte Asset-/Compliance-Nachweise aus einer kundenseitigen Abfrage, sofern einem unterstützten Zielobjekt zugeordnet

Diese Tabelle beschreibt mögliche Zuordnungen, keine mitgelieferten Direktkonnektoren. Herstellerabruf, Rechte, Paging und Bewertung müssen im kundenseitigen Adapter implementiert werden. Unbekannte Ergebnisse als unknown liefern, nicht als Erfolg.

Die eingebaute Entra-Anmeldung und AD-/Entra-Gruppenanbindung sind davon getrennte Funktionen; siehe Gruppen und Einstellungen. Der Push-Kanal provisioniert keine Benutzer oder Gruppen und ersetzt keine Verzeichnis-Konfiguration.