PRTG – Terminalserver Auslastung (Load Index) überwachen

Die Last eines Terminalservers wird in der Welt von Citrix Virtual Apps and Desktops mittels des Load Indexes angegeben. Dieser Wert geht von 0 (0% – keine Last) bis 10’000 (100% – Volllast). Volllast bedeutet ja noch nicht zwingend, dass ein Server keine Luft mehr hat, dennoch kann sich kein neuer Benutzer mehr anmelden.

Da wir die Berechnungskriterien für den Load Index selbst definieren können (z.B. CPU, RAM, Anzahl Benutzer), können wir uns im Monitoring nicht auf einen uns bekannten Wert wie z.B. die Prozessorlast verlassen.

Ich hatte daher die Idee einen Sensor zu erstellen, welcher für jede Bereitstellungsgruppe die durchschnittliche Last anhand des Load Indexes berechnet uns ausgibt.

Der Sensor selbst wird im PRTG innerhalb des Citrix Controllers erstellt und nicht pro Worker.

Im ersten Schritt werden alle Bereitstellungsgruppen vom Controller ausgelesen und in einem Array gespeichert. Es wird hier bereits geprüft, ob eine Bereitstellungsgruppe ggf. im Wartungsmodus ist.

###
# Prepare an array of all delivery groups from a Citrix controller by an Invoke-Command
# Citrix PS commands are only available on those servers
$Data = $null
$Data=@()

$Data += Invoke-Command -Computername $server -credential $credentials -ScriptBlock {

    # Load Citrix PS Snapin
    add-pssnapin citrix*

    # Get delivery groups with the needed information
    $DeliveryGroups=Get-BrokerDesktopGroup | Select-Object Name, InMaintenanceMode

    # Set the array for later work
    $DG=@()
    ForEach ($group in $DeliveryGroups){
       $DG += [PSCustomObject]@{Name=$group.Name;InMaintenance=$group.InMaintenanceMode} 
    }

    # Return data to PRTG probe
    return $DG
}

Im weiteren Schritt wird jede einzelne Bereitstellungsgruppe (DG) abgearbeitet. Ist eine DG im Wartungsmodus, dann wird ein pseudo Load Index von 99/9% zurück gegeben, damit im Monitoring kein Alarm ausgelöst wird.

Jede weitere DG wird nun erneut beim Controller abgefragt. Nun werden jedoch sämtliche Worker mit ihrem aktuellen Load Index Wert in einen Array gespeichert. Danach wird die Summe aller Lastwerte errechnet und durch die Anzahl Worker geteilt (einfache Mathematik ^^) und zu guter Letzt der Prozentwert auf eine Zahl ohne Komma gerundet, da PRTG keine Kommawerte in einem Prozentfeld ausgeben kann.

Diese Daten werden in einen weiteren Array geschrieben, welcher im Anschluss benutzt wird um die PRTG Ausgabe zu erstellen:

###
# Prepare an array of the load of all delivery groups from a Citrix controller by an Invoke-Command
# Citrix PS commands are only available on those servers
$Load = $null
$Load=@()

ForEach ($RDSHGrp in $Data) {

    $RDSHArg = $null
    $RDSHArg = $RDSHGrp.Name

    # Determine if a delivery group is in maintenance
    # DGs in maintenance goes into warning state, but doesn't affect the whole sensor
    # DGs in maintenance will not be stated based on her usage
    # DGs in maintenance will have fake values of 9% and 99 to avoid an alarm
    If ($RDSHGrp.InMaintenance) {
        $RDSHWorkers=99
        $RDSHTotalLoad=99
        $RDSHAvgLoad=99
        $RDSHAvgPercent=9
    }
    Else {
        $RDSHLoad = $null
        $RDSHLoad = @()


        $RDSHScriptBlock =
            {
                 # Load Citrix PS Snapin
                add-pssnapin citrix*

                # Get delivery groups with the needed information
                $RDSHWorker=Get-BrokerMachine | Where-Object DesktopGroupName -eq $args[0] | Select-Object DNSName, LoadIndex

                # Set the array for later work
                $RDSH=@()
                ForEach ($Worker in $RDSHWorker){
                   $RDSH += [PSCustomObject]@{Name=$Worker.DNSName;Load=$Worker.LoadIndex} 
                }

                # Return data to PRTG probe
                return $RDSH
             }

        # Get the load index of all workers in the delivery group
        $RDSHLoad += Invoke-Command -Computername $server -credential $credentials -ScriptBlock $RDSHScriptBlock -ArgumentList $RDSHArg

        # Count the workers
        $RDSHWorkers = $RDSHLoad.count
        $RDSHTotalLoad = 0
        # Calculate the sum of all load indexes
        $RDSHLoad.Load | ForEach{$RDSHTotalLoad += $_}
        # Calculate the average load index for the delivery group
        $RDSHAvgLoad = "{0:F0}" -f ($RDSHTotalLoad/$RDSHWorkers)
        # Calculate the average percent value of the load index for the delivery group
        $RDSHAvgPercent = "{0:F0}" -f ($RDSHAvgLoad/100)

    }
    $Load += [PSCustomObject]@{Name=$RDSHArg;Worker=$RDSHWorkers;TotalLoad=$RDSHTotalLoad;AvgLoad=$RDSHAvgLoad;AvgPercent=$RDSHAvgPercent}
}

Die PRTG Ausgabe selbst ist durch die vorherigen Berechnungen keine Raketenwissenschaft mehr:

###
# Prepare the data and the PRTG XML output

# Reset some variables and define standard values
$returnState=$null
$returnState=@()
$returnStateOK = 0
$returnStateWarning = 1
$returnStateCritical = 2
$AlertLevel=90
$AlertString = "ALERT - high load index"
$WarningLevel=80
$WarningString = "Warning - load index reaches a high level"

# Start preparing XML output
$retXml = "<prtg>`n"

# Get data for each delivery group from the array created on the Citrix Controller
ForEach ($Dataset in $Load){
    # Prepare variables based on the array data
    $DGName = $Dataset.Name
    $DGTotal = $Dataset.Worker
    $DGLoad = $Dataset.AvgLoad
    # Calculate the percentage of the RDSH delivery groups
    $DGLoadPercent = $Dataset.AvgPercent
    $DGMaintenance = $Dataset.Maintenance

    # Determine return state if delivery group is not in maintenance
    # The values depend on the size of the delivery group
    If ([Int64]$DGLoadPercent -gt $AlertLevel){
        $RetState = $returnStateCritical
        $returnState += [PSCustomObject]@{Name=$DGName;State=[Int64]$RetState} 
    }
    ElseIf ([Int64]$DGLoadPercent -le $WarningLevel) {
        $RetState = $returnStateOK
        $returnState += [PSCustomObject]@{Name=$DGName;State=[Int64]$RetState} 
    }
    Else {
        $RetState = $returnStateWarning
        $returnState += [PSCustomObject]@{Name=$DGName;State=[Int64]$RetState} 
    }


    #$retXml += "  <result>`n"
    #$retXml += "    <channel>$DGName State</channel>`n"
    #$retXml += "    <value>$RetState</value>`n"
    #$retXml += "  </result>`n"
    $retXml += "  <result>`n"
    $retXml += "    <channel>$DGName Load %</channel>`n"
    $retXml += "    <value>$DGLoadPercent</value>`n"
    $retXml += "    <unit>Percent</unit>`n"
    $retXml += "    <limitMode>1</limitMode>`n"
    $retXml += "    <limitMaxError>$AlertLevel</limitMaxError>`n"
    $retXml += "    <limitErrorMsg>$AlertString</limitErrorMsg>`n"
    $retXml += "    <limitMaxWarning>$WarningLevel</limitMaxWarning>`n"
    $retXml += "    <limitWarningMsg>$WarningString</limitWarningMsg>`n"
    $retXml += "  </result>`n"
    $retXml += "  <result>`n"
    $retXml += "    <channel>$DGName Load Index</channel>`n"
    $retXml += "    <value>$DGLoad</value>`n"
    $retXml += "    <unit>Count</unit>`n"
    $retXml += "  </result>`n"
}

# Determine return string depends on the several states
If ($returnState.State -contains 2) {
    $RetString = $AlertString    
}
ElseIf ($returnState.State -contains 1) {
    $RetString = $WarningString    
}
Else {
    $RetString = "OK"    
}

$retXml += "  <text>$RetString</text>`n"
$retXml += "</prtg>`n"

###
# Return info to PRTG
write-host $retXml

Das Ergebnis sieht dann wie folgt aus:

Viel Spass beim Nachbauen. :-)




Neustart nicht registrierter VDAs

Beim Start eines Workers werden bei uns mittels Startup Script noch div. Tasks abgearbeitet. Um eine Anmeldung zu verhindern, stoppt dieses Script als erstes den Citrix Desktop Dienst. Leider haben wir ab und an das Phänomen bei den Terminalservern, dass genau dieser Dienst zum Schluss entweder nicht gestartet wird oder die Registration nicht klappt.

Bisher gingen wir dann den einfach weg eines Neustarts (war sowieso kein Benutzer angemeldet). Dies habe ich nun mit einem einfachen Skript automatisiert:

# Load Citrix Cmdlets
asnp Citrix*

# Check for stopped VDAs not in maintenance mode
$UnregisteredVDAs = get-brokermachine -Filter {(InMaintenanceMode -eq $False) -and (RegistrationState -eq "Unregistered")}
$UnregisteredVDAs | FT DNSName, InMaintenanceMode, RegistrationState -AutoSize

ForEach($VM in $UnregisteredVDAs) {
    New-BrokerHostingPowerAction -Action Restart -MachineName $VM.HostedMachineName
}

Das Skript prüft nach Workern, welche nicht im Wartungsmodus und trotzdem unregistriert sind. Der geplante Task wird dann mit einem Serviceuser ausgeführt, welcher auch die entsprechenden Rechte innerhalb der VAD Umgebung besitzt.

Das Skript löst zwar noch nicht die Ursache der fehlerhaften Registrierung, aber es automatisiert den händischen Aufwand.

Viel Spass beim Nachbauen. :-)




XenDesktop 7.12 – und der Local Host Cache ist zurück

Hallo zusammen

Heute (07.12.16) ist die neue Version von XenApp/XenDesktop erschienen. Nebst vielen Neuerungen welche ihr hier nachlesen könnt, kam der Local Host Cache (LHC) zurück.

Mit diesem ist es nun wieder wie vor der Ära von Version 7.x möglich, dass der Betrieb einer XA/XD Umgebung weiterläuft, auch wenn die Verbindung zum SQL Server fehlschlägt. Im Gegensatz zum alten LHC, welcher von jedem XenApp Server lokal verwaltet (Access DB) und direkt angesteuert wurde, läuft der neue LHC in einer kleinen SQL Instanz (Local DB) und bei einem Ausfall des SQL Servers wird eine Instanz bestimmt, auf welche sich alle Controller verbinden. Da die verschiedenen LHC von den jeweiligen CCS parallel zum eigentlichen Betrieb aktuell gehalten werden, soll diese neue Variante auch einiges stabiler sein als der alte LHC.

Die Local DB ist bei einer Neuinstallation von XA/XD 7.12 standardmässig aktiv.

Bei einem Upgrade einer älteren Installation wo das Connection Leasing aktiv war, muss dieses noch deaktiviert und der LHC aktiviert werden:

Mehr und detailliertere Informationen findet ihr in den Docs.

Viel Spass beim Erfahrungen sammeln :-)




Workspace Control – nur getrennte Sitzungen übernehmen

Hallo zusammen

Wer mit Citrix Webinterface gross geworden ist kennt noch die verschiedenen Einstellungen zur Workspace Control.
Als Storefront herausgekommen ist, musste man dieses Feature in der web.config suchen. Mittlerweile ist es im GUI verfügbar aber leider noch nicht so wie wir es uns wünschen würden.

XD-SF-WorkspaceControl

Bei genauerem Hinsehen stellt man fest, dass man nicht zwischen aktiven und getrennten Sitzungen unterscheiden kann.

Wie kann man dies nun lösen?

Diese Einstellungen sind auf dem Controller versteckt und genauer gesagt im Powershell.

Mittels PS können div. Policy Regeln konfiguriert werden, welche in diesem Citrix Blog in einer guten Übersicht beschrieben sind.

In meinem Artikel gehe ich nun einfach einmal auf die Anfrage eines Kunden ein, welcher nur getrennte Sitzungen übernehmen wollte.
Während den Recherchen wurde ich in einem Forumspost fündig, dass mit XA/XD 7.6 experimentel ein neuer Parameter hinzugefügt wurde.

Als erstes muss mittels Get-BrokerEntitelmentPolicyRule der Name der gewünschten Delivery Group evaluiert werden (kann vom Studio abweichend sein).

Anschliessend schauen wir uns die Einstellungen mittels Get-BrokerEntitelmentPolicyRule NameDerDeliveryGroup an:

XD-SessionReconnect-Always

Wir sehen bei SessionReconnect, dass durch den Parameter Always eine übernahme der Sitzung jederzeit erlaubt ist.

Mittels Set-BrokerEntitelmentPolicyRule NameDerDeliveryGroup -SessionReconnect DisconnectedOnly können wir die Einstellungen so setzten, dass nur eine getrennte Sitzung übernommen werden kann:

XD-SessionReconnect-Command

Mit einer erneuten Prüfung mit dem Befehl Get-BrokerEntitelmentPolicyRule NameDerDeliveryGroup sollte es nun so aussehen:

XD-SessionReconnect-DisconnectedOnly

Ab jetzt werden nur noch getrennte Sitzungen übernommen.

Aktuell gibt es aber leider noch einen Wehmutstropfen: der Parameter ist nicht bei zugewiesenen Desktops (z.B. mit Personal vDisk) verfügbar. Ich hoffe jedoch schwer, dass Citrix uns diesen noch nachliefern wird.

Viel Spass beim Ausprobieren :-)

ab XenApp/XenDesktop 7.6




Umgang mit gepinnten Dokumenten

In einem meiner letzten Citrix XenDesktop Kursen schilderte mir ein Teilnehmer die Problematik, dass bei Ihnen die gepinnten Dokumente (also Dokumente, welche z.B. bei Word in der Taskleiste fixiert wurden) nach einer Neuanmeldung eines Benutzers nicht mehr vorhanden waren:

Taskbar-Pinned-Docs-01

Aus dieser Schilderung heraus haben wir ein wenig Brainstorming zu den möglichen Ursachen vorgenommen und hier ein wenig die Zusammenhänge:

Die eigentliche Ursache für das Verhalten ist weder bei den Roaming Profiles noch bei Citrix Profile Management zu suchen, sondern bei GPO Einstellungen welche gerne eingestellt werden:

Taskbar-Pinned-Docs-02

Clear history of recently opened documents on exit

Diese Einstellung bewirkt, dass Dateien während einer Benutzersitzung in der Taskleiste erscheinen und auch angepinnt werden können.
Beim Abmelden werden diese jedoch gelöscht.
Dieses Verhalten kann falls gewünscht mittels Citrix Profile Management angepasst werden.

Do not keep history of recently opened documents

Diese Einstellung bewirkt, dass Dateien selbst während einer Benutzersitzung in der Taskleiste gar nicht erst erscheinen und somit nicht angepinnt werden können.
Dieses Verhalten kann selbst mit Citrix Profile Management nicht angepasst werden.

***

Lösungsansatz mittels Citrix Profile Management (CPM)

Mittels CPM können die einmal geöffneten Dateien in das Profil übernommen werden, so dass diese auch nach einer Neuanmeldung des Benutzers noch verfügbar sind.
Dazu wird folgender Pfad einmal ein den durch CPM verarbeiteten Ordner ausgeschlossen dafür mittels Ordner-Spiegelung während der Sitzung gleich in die Profilfreigabe geschrieben:

!ctx_roamingappdata!\Microsoft\Windows\Recent\AutomaticDestinations

Danach sind die gepinnten Dokumente auch nach einer Neuanmeldung noch vorhanden:

Taskbar-Pinned-Docs-03

Ich hoffe, ich konnte dem einen oder anderen ein wenig weiterhelfen :-)

Viel Erfolg beim Nachbau…




XML Dienste & Citrix Director gemeinsam hinter NetScaler

Hey NetScaler Fans

Ich habe in meiner Umgebung folgendes Szenario:
– zwei XenDesktop Controller auf welchen auch Director installiert ist
– einen Loadbalancing (LB) vServer auf dem NetScaler, welcher beide Server ansteuert

Ziel war es:
– den SSL LB vServer für XML-Anfragen zwischen Storefront und Controller zu verwenden mit Hostname = xmlxd7.domain.pit
– den gleichen SSL LB vServer für den Zugriff auf die Director Site zu verwenden mit Hostname = director.domain.pit
… bis hierher noch kein Problem, aber
– beim Zugriff auf den Hostname director.domain.pit soll der NetScaler im Bedarfsfall auf die URL /Director umleiten, aber KEINESFALLS wenn eine XML Anfrage den LB vServer erreicht

Soweit so gut, das Loadbalancing einrichten ist soweit ja mal keine Hexerei:

add server pit-xd01 192.168.100.31
add server pit-xd02 192.168.100.32

add service svc-https-pit-xd-01 pit-xd01 SSL 443
add service svc-https-pit-xd-02 pit-xd01 SSL 443

add lb vserver lb-vsrv-PIT-XD-HTTPS SSL 192.168.100.30 443 -persistenceType SOURCEIP -timeout 1440

bind lb vserver lb-vsrv-PIT-XD-HTTPS svc-https-pit-01
bind lb vserver lb-vsrv-PIT-XD-HTTPS svc-https-pit-02

add ssl certKey lb-server-cert -cert lb-server.cert -key lb-server.key
add ssl certKey PIT-CA -cert PIT-CA.cer
link ssl certKey lb-server-cert PIT-CA 
bind ssl vserver lb-vsrv-PIT-XD-HTTPS -certkeyName lb-server-cert

Im DNS müssen nun zwei Host-Einträge für den neuen vServer erstellt werden:
xmlxd7.domain.pit = 192.168.100.30
director.domain.pit = 192.168.100.30

Jetzt folgt der kniffligere Teil – die Umleitung für die Director URL.
Dies ist mit einer Responder Policy zu lösen, welche
– den Hostname überprüft (startet der Hostename mit director…?)
– prüft, ob die URL den Wert „director“ noch nicht enthält – unabhängig der GROSSklein Schreibung
– nach /director umleitet, sofern oben genannte Bedingungen zutreffen:

add responder action Resp_Act_to_Director redirect "\"/Director\"" -responseStatusCode 302

add responder policy Resp_Pol_to_Director "HTTP.REQ.HOSTNAME.STARTSWITH(\"director\") && HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(\"director\").NOT" Resp_Act_to_Director

bind lb vserver lb-vsrv-PIT-XD-HTTPS -policyName Resp_Pol_to_Director -priority 100 -gotoPriorityExpression END -type REQUEST

Mit dieser Responder Policy ist nun auch dieses Ziel erreicht.

Und als Abschluss noch dies…
Der aufmerksame Leser hat festgestellt, das der LB vServer für XML und Director auf Port 443 (HTTPS) reagiert. Bei der Eingabe geht dies jedoch des öftern mal vergessen. Dafür kann man einen weiteren LB vServer mit einer Umleitung einrichten:

add lb vserver http_redirect-director.domain.pit HTTP 192.168.100.30 80 -redirectURL "https://director.software-online.ch"

Viel Erfolg beim Nachbauen :-)

 

Skript: NS-XMLandDirector




ICA Auflösungsprobleme bei verstellten DPI

Hallo Citrix Freunde

Ich hatte gerade einen interessanten Supportfall.

Der Benutzer hat auf seinem lokalen Rechner die DPI Einstellung verändert (im konkreten Fall auf 150 DPI):

CR-ChangeDPI-2

Sobald der Benutzer eine ICA Sitzung startet wird diese entsprechend der DPI Werte skaliert und kann nicht verändert werden:

CR-ChangeDPI-1 CR-ChangeDPI-3

Folgende Einstellungen bei den Prozessen wfcrun32.exe und wfica32.exe sorgen für Abhilfe.

CR-ChangeDPI-4

Ob dieser Workaround für ewig funktioniert oder nur temporär entzieht sich meinen Kenntnissen. Diese Informationen habe ich netterweise vom Partner erhalten mit welcher wegen dem Problem an uns gelangte, die „Lösung“ jedoch selbst gefunden hat.

 




Citrix Director ohne SSL Check

Hallo zusammen

Wer schon mit Citrix Director gearbeitet hat, ist sicher schon über die folgende Meldung gestolpert:

Director-SSLCheckMessage

Die von der Installation angelegte Verknüpfung verweist auf eine HTTP URL und nicht HTTPS, was zur Sicherheitsmeldung führt. Falls diese störend sein sollte, so kann diese im IIS deaktiviert werden.

Dazu öffnet man die Director Site im IIS Manager und wählt die Application Settings:

Director-IIS-ApplicationSettings

Sobald man den Parameter UI.EnableSSLCheck auf False ändert, verschwindet auch die Meldung.

Director-IIS-ApplicationSettings-UIEnableSslCheckFalse

Director-noSSLCheckMessage

Weitere Informationen: http://support.citrix.com/article/CTX135749
(Beschreibung ganz unten)

—–

ab Director 7.x




Citrix Director ohne Applikationen

Hallo zusammen

Director ist meines Erachtens wirklich ein brauchbares Tool für den Helpdesk. Eine Problematik kann jedoch das Tab Applications innerhalb der Benutzerdetails darstellen. Der Helpdesk sieht da die komplette Titelleiste der geöffneten Applikationen und sind wir ehrlich, gewisse Dinge (Dateinamen, Homepage-Titel, etc.) gehen den Helpdesk nur bedingt etwas an:

Director-with-Apps-DE

Um dies zu vermeiden kann man die Übermittlung der Daten entweder mittels Registry-Anpassung seitens VDA unterdrücken oder man deaktiviert die Darstellung innerhalb des Director Frontends.

Dazu öffnet man die Director Site im IIS Manager und wählt die Application Settings:

Director-IIS-ApplicationSettings

Sobald man den Parameter UI.TaskManager.EnableApplications auf False ändert, verschwinden zwar die Applikationen jedoch die Prozesse bleiben sichtbar und können weiterhin von den berechtigten Helpdesk-Mitarbeitern geschlossen werden.

Director-IIS-ApplicationSettings-UIEnableAppsFalse

Director-without-Apps

—–

ab Director 7.x