Du automatisierst Abfragen gegen deine NetScaler, etwa einen Zertifikatsbericht, eine Bestandsabfrage oder eine Konfigurationsprüfung. Statt jede Appliance einzeln anzusprechen, gehst du per NITRO über die ADM-Konsole und lässt die Konsole die Anfrage an die Instanz weiterreichen. Ein Skript, eine Anmeldung, alle Geräte.
Nur kommt statt der Antwort zurück, die Instanz sei nicht verfügbar. Oder, etwas kryptischer:
errorcode: 10005
message: Invalid Resource
Also prüfst du die Instanz. Sie antwortet auf Ping. In der ADM-Oberfläche steht sie auf „Up“. Du meldest dich direkt an ihr an, funktioniert einwandfrei. Du fragst dieselbe Ressource direkt beim NetScaler ab, die Antwort kommt sofort.
Die Instanz ist in Ordnung. Sie war es die ganze Zeit.
Die Fehlermeldung beschreibt schlicht etwas anderes, als sie behauptet. Und weil sie in die falsche Richtung zeigt, verliert man damit gern einen halben Abend.
Der ADM-Proxy meldet „Instanz nicht erreichbar“ auch dann, wenn er die Anfrage selbst nicht verstanden hat.
Er kann an dieser Stelle nicht zwischen „ich komme nicht hin“ und „ich weiß nicht, wohin“ unterscheiden, und entscheidet sich für die erste Formulierung.
Es gibt drei Ursachen, die alle nichts mit der Instanz zu tun haben. In der Reihenfolge, in der sie mir begegnet sind.
Ursache 1: Der Proxy-Header ist anders geschrieben, als du denkst
Das ist mit Abstand der häufigste Fall und der ärgerlichste, weil nichts darauf hindeutet.
Damit die Konsole eine Anfrage an eine verwaltete Instanz weiterreicht, muss im Header der Anfrage stehen, um welche Instanz es geht. Der Name dieses Headers hat sich zwischen den Releases geändert:
| Release der Konsole | Schreibweise des Headers |
|---|---|
| ab 14.1 / 72.x | MPS-API-PROXY-MANAGED-INSTANCE-IP mit Bindestrichen |
| ältere Releases | _MPS_API_PROXY_MANAGED_INSTANCE_IP mit Unterstrichen, führender Unterstrich |
Die Citrix-Dokumentation zum API-Proxy führt nur noch die Schreibweise mit Bindestrichen.
Schickst du die falsche Variante, passiert etwas Unangenehmes: Die Konsole lehnt die Anfrage nicht ab. Sie nimmt sie an, findet kein Ziel darin und behandelt sie, als wäre die Instanz nicht erreichbar. Heraus kommt errorcode 10005.
Ein Zeichen Unterschied im Header, und die Fehlermeldung zeigt auf ein Gerät, das gar nicht beteiligt ist.
Die Lösung, die das Problem dauerhaft beseitigt
Schick beide. Header, die der Empfänger nicht kennt, ignoriert er. Es entsteht kein Schaden, und du musst den Release nicht abfragen, bevor du eine Anfrage stellst.
$kopf = @{
'MPS-API-PROXY-MANAGED-INSTANCE-IP' = $Nsip # ab 14.1 / 72.x
'_MPS_API_PROXY_MANAGED_INSTANCE_IP' = $Nsip # ältere Releases
}
Das ist kein Pfusch, sondern der einzige Weg, der über einen gemischten Bestand hinweg funktioniert. Und in gewachsenen Umgebungen steht selten überall derselbe Release.
Ursache 2: „Prompt Credentials for Instance Login“ ist eingeschaltet
Wenn Ursache 1 ausscheidet und die Meldung stattdessen so aussieht:
instance credentials not found
…dann ist der Proxy in Ordnung und die Schreibweise stimmt. Es fehlt etwas anderes.
In den Systemeinstellungen der Konsole gibt es einen Schalter:
Settings → Administration → System, Time Zone, Allowed URLs and Agent Settings → Basic Settings → Prompt Credentials for Instance Login
Die Kachel steht im Bereich System Configurations. So heißt sie auf meiner Testinstanz mit der Konsole 14.1 Build 72.57. Die Citrix-Dokumentation nennt sie teils System, Time zone, Allowed URLs and Message of the day.
Ist er aus (Voreinstellung), meldet sich die Konsole mit dem hinterlegten Instanzprofil an der Appliance an. Deine Anfrage braucht nur die Konsolensitzung.
Ist er an, tut sie das nicht mehr. Sie verlangt pro Anfrage Anmeldedaten für die Instanz, als zusätzliche Header (…-INSTANCE-USERNAME / …-INSTANCE-PASSWORD, alternativ …-INSTANCE-SESSID, vollständig in der Dokumentation zum API-Proxy). Fehlen sie, kommt instance credentials not found.
Das ist eine bewusste Sicherheitsentscheidung: Nicht jeder, der sich an der Konsole anmelden darf, soll damit automatisch auf jeder verwalteten Appliance arbeiten können.
Die Falle dabei
Jetzt wird es unangenehm. Der naheliegende Reflex lautet: „Dann schicke ich die Anmeldedaten einfach immer mit, dann passt es in beiden Fällen.“
Das geht schief. Auf einer Konsole, bei der der Schalter aus ist, erzeugt das Mitschicken der Anmelde-Header einen HTTP 404.
| Schalter | ohne Anmelde-Header | mit Anmelde-Header |
|---|---|---|
| aus (Voreinstellung) | ✅ funktioniert | ❌ HTTP 404 |
| an | ❌ instance credentials not found |
✅ funktioniert |
Bei den Proxy-Headern aus Ursache 1 darfst du beide Varianten schicken. Hier darfst du es nicht. Der Unterschied ist, dass ein unbekannter Ziel-Header ignoriert wird, ein unerwarteter Anmelde-Header dagegen einen anderen Verarbeitungspfad auslöst.
Du musst also wissen, wie die Konsole eingestellt ist. Ein Rundumschlag funktioniert nicht.
Und wenn du die Einstellung nicht ändern darfst?
Das ist der häufige Fall. Der Schalter ist aus gutem Grund an, und die Konsole gehört nicht dir.
Dann hör auf, gegen den Proxy zu kämpfen, und geh direkt auf die Appliance. Der Proxy ist eine Bequemlichkeit, kein Selbstzweck. Was du über ihn abfragen wolltest, kannst du genauso gut direkt abfragen. Du brauchst nur eine zweite Anmeldung.
Der Proxy spart dir eine Anmeldung. Er ist es nicht wert, dafür eine Sicherheitseinstellung abzuschalten, die jemand bewusst gesetzt hat.
Wichtig beim Direktzugriff: über HTTPS und über den Namen, nicht über die IP. Löse die NSIP per Reverse-DNS auf und verwende den vollständigen Namen. Dann passt der Name im Zertifikat, und die Prüfung läuft regulär durch. Der Weg „IP plus Zertifikatsprüfung aus“ ist bequem und genau deshalb gefährlich: Er wird nie wieder zurückgebaut.
So arbeitet auch das Prüfskript aus dem Beitrag NetScaler CVE-2026-88771 bis 88778: Betroffenheit prüfen: Es fragt jede Appliance direkt per NITRO über HTTPS und den FQDN ab, ohne Umweg über die Konsole.
Und noch ein Hinweis, der einen eigenen Abend kosten kann: Der Management-Zugriff auf einen NetScaler ist in Produktivumgebungen meist nur über HTTPS möglich, Port 80 ist zu. Eine Meldung „Verbindung abgelehnt“ heißt dort falscher Port, nicht Zertifikatsproblem. Zwei völlig verschiedene Fehlerbilder, die gern verwechselt werden.
Ursache 3: Ein Schrägstrich zu viel
Die unscheinbarste der drei, und deshalb die, die am längsten unentdeckt bleibt.
Steht die Basisadresse der Konsole mit abschließendem Schrägstrich in deiner Konfiguration, ergibt das Zusammensetzen der Adresse einen doppelten Schrägstrich:
https://adm.example.local/ + /nitro/v1/config/…
→ https://adm.example.local//nitro/v1/config/…
→ HTTP 404
Das sieht man nicht, weil man die zusammengesetzte Adresse normalerweise nicht ausgibt. Und ein 404 lenkt den Verdacht sofort auf einen falschen Ressourcennamen, also sucht man an der falschen Stelle weiter.
# Beim Einlesen einmal abschneiden, dann nie wieder darüber nachdenken
$AdmUrl = $AdmUrl.TrimEnd('/')
Wie du die drei in zwei Minuten auseinanderhältst
Die Fehlermeldung sagt dir mehr, als es zunächst aussieht, wenn du weißt, welche zu welcher Ursache gehört:
| Was zurückkommt | Ursache | Was zu tun ist |
|---|---|---|
errorcode 10005 / Invalid Resource |
1, Schreibweise des Headers | beide Schreibweisen schicken |
instance credentials not found |
2, Schalter ist an | Instanz-Anmeldedaten mitschicken oder direkt auf die Appliance |
| HTTP 404 trotz korrektem Ressourcennamen | 3, doppelter Schrägstrich | .TrimEnd('/') |
| HTTP 404, aber nur wenn du Anmeldedaten mitschickst | 2, Schalter ist aus | Anmelde-Header weglassen |
Der vollständige Ablauf, der die Frage abschließend klärt:
# 1. An der Konsole anmelden. Wichtig: Der Body beginnt hier mit 'object='
# (beim direkten Zugriff auf die Appliance ist es reines JSON ohne dieses Praefix).
$AdmUrl = 'https://adm.example.local'.TrimEnd('/')
$anmeldung = @{
login = @{
username = $Cred.UserName.Split('\')[-1] # ohne Domaenenanteil
password = $Cred.GetNetworkCredential().Password
}
} | ConvertTo-Json -Depth 3
$null = Invoke-RestMethod -Method Post -Uri "$AdmUrl/nitro/v1/config/login" `
-Body "object=$anmeldung" -ContentType 'application/json' `
-SessionVariable sitzung
# 2. Abfrage OHNE Proxy: beantwortet die Konsole selbst?
# Kommt hier etwas zurueck, ist die Anmeldung in Ordnung und das Problem liegt am Proxy.
Invoke-RestMethod -Uri "$AdmUrl/nitro/v1/config/managed_device" -WebSession $sitzung |
Select-Object -ExpandProperty managed_device |
Select-Object ip_address, instance_state, type -First 5
# 3. Abfrage MIT Proxy, beide Schreibweisen des Headers
$kopf = @{
'MPS-API-PROXY-MANAGED-INSTANCE-IP' = '10.0.0.10'
'_MPS_API_PROXY_MANAGED_INSTANCE_IP' = '10.0.0.10'
}
Invoke-RestMethod -Uri "$AdmUrl/nitro/v1/config/nsversion" `
-Headers $kopf -WebSession $sitzung
Schritt 2 ist der eigentliche Trick. Er trennt die Frage „komme ich an der Konsole überhaupt an?“ von der Frage „reicht sie meine Anfrage weiter?“. Antwortet Schritt 2, Schritt 3 aber nicht, liegt es am Proxy, und die Instanz war nie das Thema.
Die Anmeldung selbst hat übrigens eine eigene Tücke, die sich als „falsches Kennwort“ tarnt: Der Benutzername muss ohne Domänenanteil übergeben werden. DOMAENE\lars wird abgelehnt, lars angenommen. Deshalb steht oben .Split('\')[-1].
Ein Nachtrag, der Zeit spart
Beim Abmelden von der Konsole wirft manche Version einen HTTP 405, obwohl die Abmeldung funktioniert hat. Wenn dein Ablauf am Ende scheitert, obwohl alles davor sauber lief, ist meist das die Ursache. Fang den Fehler beim Abmelden mit try/catch ab, damit der Ablauf nicht daran scheitert.
Was du dir merkst
„Instanz nicht verfügbar“ ist beim ADM-Proxy fast nie eine Aussage über die Instanz.
Es ist eine Aussage darüber, dass die Konsole mit deiner Anfrage nichts anfangen konnte. Sie kann an dieser Stelle nicht unterscheiden, ob sie das Ziel nicht erreicht oder nicht erkannt hat.
Prüf die Reihenfolge: Schreibweise des Headers, dann den Schalter für die Instanz-Anmeldung, dann den Schrägstrich. Und wenn der Schalter an ist und du ihn nicht ändern darfst, geh direkt auf die Appliance. Der Proxy spart eine Anmeldung, mehr nicht.
Quellen
- NetScaler Console als API-Proxy-Server, Citrix-Dokumentation: Header, Instanz-Anmeldedaten und der Hinweis zu Prompt Credentials for Instance Login
Die Schreibweise des Proxy-Headers ist releaseabhängig und kann sich mit künftigen Versionen erneut ändern. Deshalb beide Varianten schicken, statt eine fest zu verdrahten.
