Terminalserver 2016 - sehr lange Anmeldezeiten

Problem

Die Anmeldung an Windows Terminalserver 2016 dauert sehr lange, zum Teil bis zu 15 Minuten. Ich gebe hier zwei Lösungen wieder. Wie immer gilt: Nutzung auf eigene Verantwortung.

Lösung 1

Ablauf

Auf dem betreffenden Terminalserver mit

mstsc /admin

als Domänenadministrator anmelden.

Registrierung sichern

Diesen Bereich der Registrerung exportieren.

HKEY_LOCAL_MACHINE
 \System
  \CurrentControlSet
   \Services
    \SharedAccess
     \Parameters
      \FirewallPolicy
       \RestrictedServices
        \Configurable
         \System

Einträge der Registrierung löschn

In der Eingabeaufforderung dieses Kommando starten. Umbrüche sind Platzbedingt

reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Configurable\System" /va /f

Neue Gruppenrichtlinie einrichten

Es muss ein neuer Eintrag in der Registrierung vorgenommen werden. Das soll über die Gruppenrichtlinienverwaltung geschehen.

Benutzerkonfiguration
 Einstellungen
  Windows-Einstellungen
   Registrierung

Darin dann einen neuen Ordner und einen neuen Eintrag erstellen.

Registerkarte Allgemein

Aktion: Ersetzen
Struktur: HKEY_LOCAL_MACHINE
Schlüsselpfad: SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy
Eintrag unter Name: DeleteUserAppContainersOnLogoff
Werttyp: REG_DWORD
Wertdaten: 00000001
Basis: Hexadezimal
Registerkarte Gemeinsame Optionen

keine Einträge

Gruppenrichtlinie aktualisieren

In der Eingabeaufforderung dies eingeben.

gpupdate /force

Windows PowerShell ISE

Auf dem betreffenden Terminalserver die Windows PowerShell ISE aufrufen. Dazu das Startmenü öffnen, 'PowerShell ISE' zu tippen beginnen und den Vorschlag akzeptieren.

Darin dann den Skriptbereich anzeigen lassen. Im Menü:

Ansicht, Skriptbereich anzeigen Strg + r

In 'Unbenannt1.ps' dies hier einfügen und mit einem Klick auf das grüne Dreieck ausführen lassen. Umbrüche sind platzbedingt.

$FWInboundRules       = Get-NetFirewallRule -Direction Inbound |Where {$_.Owner -ne $Null} | sort Displayname, Owner 
$FWInboundRulesUnique = Get-NetFirewallRule -Direction Inbound |Where {$_.Owner -ne $Null} | sort Displayname, Owner -Unique 

Write-Host "# inbound rules         : " $FWInboundRules.Count
Write-Host "# inbound rules (Unique): " $FWInboundRulesUnique.Count 

if ($FWInboundRules.Count -ne $FWInboundRulesUnique.Count) {
Write-Host "# rules to remove       : " (Compare-Object -referenceObject $FWInboundRules  -differenceObject $FWInboundRulesUnique).Count
Compare-Object -referenceObject $FWInbouIn unterschendRules  -differenceObject $FWInboundRulesUnique   | select -ExpandProperty inputobject |Remove-NetFirewallRule } 

Wenn Skript 1 durchgelaufen ist mit [Strg] + [n] eine neue Registerkarte aufrufen. In 'Unbenannt2.ps' dies hier einfügen und mit einem Klick auf das grüne Dreieck ausführen lassen. Umbrüche sind platzbedingt.

$FWOutboundRules       = Get-NetFirewallRule -Direction Outbound |Where {$_.Owner -ne $Null} | sort Displayname, Owner 
$FWOutboundRulesUnique = Get-NetFirewallRule -Direction Outbound |Where {$_.Owner -ne $Null} | sort Displayname, Owner -Unique 
Write-Host "# outbound rules         : : " $FWOutboundRules.Count
Write-Host "# outbound rules (Unique): " $FWOutboundRulesUnique.Count 
if ($FWOutboundRules.Count -ne $FWOutboundRulesUnique.Count)  {
Write-Host "# rules to remove       : " (Compare-Object -referenceObject $FWOutboundRules  -differenceObject $FWOutboundRulesUnique).Count
Compare-Object -referenceObject $FWOutboundRules  -differenceObject $FWOutboundRulesUnique   | select -ExpandProperty inputobject |Remove-NetFirewallRule} 

Es hat sich als hilfreich gezeigt, die Skripte erneut nacheinander ausführen zu lassen. Dann sollten sie jeweils in deutlich kürzerer Zeit durchgelaufen sein.

Bei Bedarf Drucker neu verbinden

Es dauert zum Teil sehr lange, bis die Verbindungen zu den Druckern über eine Gruppenrichtlinie hergestellt sind (wird hier nicht beschrieben). Darum über das Netzwerk die Drucker des Druckserver markieren und über einen Rechtsklick mit allen verbinden.

Quelle:
https://social.technet.microsoft.com/Forums/en-US/992e86c8-2bee-4951-9461-e3d7710288e9/windows-servr-2016-rdsh-firewall-rules-created-at-every-login?forum=winserverTS


Lösung 2

Eine andere Möglichkeit ist es, die auf dem Druckserver freigegebenen Drucker nicht über eine Gruppenrichtlinie, sondern über KIX zuzuordnen. Dabei wird vorausgesetzt, dass eventuell vorhandene Gruppenrichtlinien für die Druckerzuweisung deaktiviert sind. Die nun erforderlichen Dateien liegen in der Netlogon-Freigabe des Domänencontrollers. In den Eigenschaften der betreffenden Benutzerkonten wird unter der Registerkarte 'Profil' bei 'Anmeldeskript' der betreffende Skriptname hinterlegt. In diesem Beispiel 'loginskript'.

'loginskript'

@echo off
echo ***************************************
echo Guten Tag Benutzer/in
echo Viel Spass bei der Arbeit.
echo.
echo Domaene        : %userdomain%
echo Betriebssystem : %os%
echo Prozessor      : %PROCESSOR_IDENTIFIER%
echo ***************************************
echo.

echo Weitere Skripte aufrufen
call %logonserver%\netlogon\wts-printer.cmd
call %logonserver%\netlogon\anderes-skript.cmd
call %logonserver%\netlogon\weiteres-skript.cmd

Das Logonskript ruft (ein) weitere(s) Skript(e) auf.

'wts-printer.cmd'

Hier ist eine Abfrage hinterlegt, die, je nachdem, an welchem Terminalserver die Anmeldung stattfindet, ein entsprechendes Skript aufruft. In diesem Fall ist es möglich, unterschiedliche Druckserver zu nutzen. Das ist zum Beispiel bei einer Migration vorteilhaft, wenn die Terminalserver der einen Gruppe / Farm einen anderen Druckserver nutzen sollen. Die Benennung bzw. Nummerierung der Terminalserver mit einer oder zwei Ziffern ist Absicht. Dahinter stehen Server unterschiedlicher Betriebssysteme, wie es beispielsweise bei der Migration von Server 2008 auf Server 2016 vorkommen mag.

@echo on
echo Netzwerkdrucker einrichten einrichten

if "%computername%"=="DOMAENETS01" (
	goto TSPrinterDrucker01
  )

if "%computername%"=="DOMAENETS02" (
	goto TSPrinterDrucker01
  )

if "%computername%"=="DOMAENETS03" (
	goto TSPrinterDrucker01

if "%computername%"=="DOMAENETS1" (
	goto TSPrinterDrucker03
  )

if "%computername%"=="DOMAENETS2" (
	goto TSPrinterDrucker03
  )

if "%computername%"=="DOMAENETS3" (
	goto TSPrinterDrucker03
  ) else (
	exit
  )

:TSPrinterDrucker01
kix32.exe login-drucker01.kix
goto ende

:TSPrinterDrucker03
kix32.exe login-drucker03.kix
goto ende

:ende

In unserem Beispiel wird 'login-drucker01.kix' aufgerufen.

'login-drucker01.kix'

Dieses Skript kann unter anderem Namen für andere Terminalserver und einen anderen Druckserver genutzt werden, bei einer Migration zum Beispiel. Verwendet wird kix.exe Version 4.67.0.0

; ***************************************************************
; KIX32-Login-Script fuer alle Benutzer
; Druckerverbindungen fuer Benutzer erstellen
; ***************************************************************

? "Druckerverbindungen für Benutzer [" + @USERID + "] erstellen:"

; -----
; ? "-> Vorhandene Netzwerkdrucker entfernen"
; Deaktiviert, weil bei doppelter Anmeldung
; die Drucker beim einer Abmeldung auch bei
; der anderen Abmeldung entfernt werden.

; $objNetwork = createobject("WScript.Network")
; $objPrinters = $objNetwork.EnumPrinterConnections
; For $intLoop = 0 to $objPrinters.Count - 1
;  $=DELPRINTERCONNECTION($objPrinters.Item($intLoop))
; Next
; -----

? "-> Neue Netzwerkdrucker installieren"

; Datei mit Druckerzuordnungen oeffnen
IF Open(3, "%logonserver%\netlogon\user_ts-drucker01.csv")  = 0

   ; Erste Zeile einlesen
   $s = ReadLine(3)

   WHILE @ERROR = 0

      ; Zeile in Array aufsplitten
      $spalten = Split($s,";")

      ; Steht in der ersten Spalte der aktuelle Benutzer ?
      if UCASE($spalten[0]) == UCASE(@USERID) 

        ; Drucker verbinden
        If AddPrinterConnection ($spalten[1]) = 0
          ? "-> Drucker ["+$spalten[1]+"] verbunden"

          ; Soll der Drucker als Standard gesetzt werden ?
          if UCASE($spalten[2]) == "J"

            ; Standarddrucker setzen
            If SetDefaultPrinter ($spalten[1]) = 0
              ? "-> Standarddrucker gesetzt auf ["+$spalten[1]+"]"
            Endif

          endif

        Endif

      endif
      
      ; Nächste Zeile einlesen
      $s = ReadLine(3)

   LOOP

   ; Datei schließen
   $ = Close (3)

ELSE
   BEEP
   ? "Druckerzuordnungsdatei konnte nicht geoeffnet werden! Fehler-Code: [" + @ERROR + "]"
ENDIF

; Neue Zeile
?

Man kann erkennen, dass 'user_ts-drucker01.csv' aufgerufen wird. Darin stehen nun die Usernamen und die Namen der auf dem Druckserner freigegebenen Drucker.

Wenn etwas geändert werden muss, dann muss lediglich in dieser Datei eine Zeile geändert werden.
';J' sorgt dafür, dass der Drucker ein Standarddrucker ist. Darf also je User nur einmal vorkommen.
';N' ordnet den Drucker zu, ohne dass er Standarddrucker ist.

'user_ts-drucker01.csv'

Der Druckserver heißt 'domaeneprn01'. 'user01' hat lediglich einen Drucker zugeordnet bekommen, während 'user02' das selbe Druckgerät mit unterschiedlichen Einstellungen zugeordnet bekommt.

user01;\\domaeneprn01\drucker01-weiss-einseitig;J
user02;\\domaeneprn01\drucker01-weiss-einseitig;J
user02;\\domaeneprn01\drucker01-weiss-duplex;N
user02;\\domaeneprn01\drucker01-briefbogen-einseitig;N
user02;\\domaeneprn01\drucker01-briefbogen-duplex;N


Bei einem Test hat sich gezeigt, dass mit Lösung 1 die Anmeldung mitunter weiterhin mehrere Minuten dauerte. Es gab eine Besserung.

Mit Lösung 2 konnte die Anmeldung auf maximal fünfundvierzig Sekunden verkürzt werden konnte. Beim Anmelden läuft in einer minimierten cmd die Druckeranbindung weiter. Darum ist es hilfreich, jedem User den Standarddrucker zuerst zuzuordnen, also die Zeile, die mit 'J' den Drucker als Standarddrucker zuordnet, als erstes aufzuführen.

User werden mit Lösung 2 zwar schnell angemeldet, die Druckerzuordnung dauert dennoch weiterhin etwas länger. Allein das fällt dann nicht mehr so auf. So kann man weiter nach der Ursache suchen, warum die Druckerzuordnung über GPO so lange dauert.