Event 7031 MSExchangeDiagnostics Exchange 2016

Ein weiterer Fehler in Exchange 2016 CU 1  ist das der Service MSExchangeDiagnostics immer wieder abstürzt. Schauen wir doch mal ob wir diesen Fehler beheben können.

Problem:

Das Event 7031 meldet das der Dienst MSExchangeDiagnostics gecrasht ist und neu gestartet wurde. Vorgelagert ist ein Event mit der ID 4999 „MSExchange Common“, der versucht das Microsoft Exchange Diagnostics Log zu starten.

Meldung im Log:

The Microsoft Exchange Diagnostics service terminated unexpectedly.  It has done this 673 time(s).  The following corrective action will be taken in 60000 milliseconds: Restart the service.

Analyse:

Im Log C:\Program Files\Microsoft\Exchange Server\V15\Logging\Diagnostics\ServiceLogs\DiagnosticsServiceLog<Datum>.txt sieht man u.a. wie der Dienst versucht den Task ExchangeDiagnosticsPerformanceLog zu starten. Das gelingt nicht weil der Task nicht existiert. In der Registry unter HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\Microsoft\Windows\PLA\ steht der Task aber drin. OK, hier liegt das Problem.

Lösung:

Unter HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\Microsoft\Windows\PLA\ die Einträge ExchangeDiagnosticsDailyPerformanceLog und ExchangeDiagnosticsPerformanceLog löschen. Danach den Server neu starten und schon existieren die Registry Werte wieder und auch in der GUI ist alles vorhanden. Die Events 7031 verschwinden somit.

000818

Event 106 MSExchange Common Exchange 2016

Wie jeder gute Exchange Administrator versuche auch ich möglichst  alle Fehler nach einer neuen Installation zu bereinigen, damit man im Fehlerfall den Wald vor lauter Bäumen nicht sieht. Nun habe ich Microsoft Exchange 2016 neu installiert mit CU1 und diese Events 106 haben sehr genervt. Hier mal ein Ansatz wie man diesen Fehlern begegnen kann.

Fehlermeldung im Application Log:

Performance counter updating error. Counter name is Percentage of MSAUserNetID Cache hits for last minute, category name is MSExchange Global Locator Processes. Optional code: 3. Exception: The exception thrown is : System.InvalidOperationException: The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.

weiter unten im Fehler steht folgendes:

Performance Counters Layout information: FileMappingNotFoundException for category MSExchange Global Locator Processes : Microsoft.Exchange.Diagnostics.FileMappingNotFoundException: Cound not open File mapping for name Global\netfxcustomperfcounters.1.0msexchange global locator processes.

Analyse Teil 1:

Scheinbar fehlt hier eine Datei bzw. sie wird nicht gefunden. Aber welche ist das? Klar es hat was mit .NET Framework zu tun. (P.S. Ich hatte das Feature .NET Framework 3.5 auf meinen Exchange Servern installiert, um die Event 1023 Perflib für MSExchangeIS zu beseitigen.) Also versuchen wir doch mal alle Performance Counter in der Registry neu einzulesen. Einmal den Befehl mit erhöhten Rechten ausführen:

c:\windows\system32>lodctr /r

Das Vorgang dauert ein wenig und in der Console wird am Ende ggf. ein Fehler angezeigt.

Error: Unable to rebuild performance counter setting from system backup store, error code is 2

OK, da stimmt was nicht, also schnell mal in das Application Log schauen, welche Counter nicht funktionieren.

000816

Bei mir funktionieren folgende Counter nicht:

.NET CLR Data service,  .NET CLR Networking service, .NET Data Provider for Oracle service, .NET Data Provider for SqlServer service und .NETFramework service

Alle Counter gehören zum .NET Framework service, also schauen wir in der Registry nach welche Datei geladen werden soll. Unter HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\.NETFramework\Performance\PerfIniFile finden wird die nötige ini Datei. In meinem Fall ist das die „corperfmonsymbols_d.ini“. Eine Suche unter C:\Windows ergab, das die Datei in C:\Windows\Inf\.NETFramework\0000 liegt. Der Inhalt der Datei ist ernüchternd und verweist auf die „corperfmonsymbols.ini“, die ich unter C:\Windows\Inf\.NETFramework fand. Die Datei ist richtig, also sollten wir diese Datei nutzen um die Performance Counter neu zu laden.

Lösung Teil 1:

c:\windows\system32>lodctr C:\Windows\Inf\.NETFramework\corperfmonsymbols.ini

Im ApplicationLog sehen wir jetzt ein Event 1000 indem folgendes steht: Performance counters for the .NETFramework (.NETFramework) service were loaded successfully. The Record Data in the data section contains the new index values assigned to this service.

Wenn wir jetzt erneut die Performance Counter neu einlesen, dann funktioniert alles wunderbar:

000817

Aber:

Nach einem Neustart des Servers sieht man die 106 er Events erneut. Aber die Basis .NET Performance Counter sind in Ordnung – das haben wir geprüft. Also weiter mit der Analyse …

Analyse Teil 2:

Warum und wozu werden die Performance Counter benutzt bzw. aufgerufen, wenn sie gleich beim Systemstart fehl schlagen? Ein Blick in die Registry verrät die Quelle: Die Tasks \Microsoft\Windows\PLA\ExchangeDiagnosticsDailyPerformanceLog und ExchangeDiagnosticsPerformanceLog nutzen diese Performance Counter. OK, das sind die Standard Tasks für Exchange Performance. (P.S. bei Fehler diesen Eintrag lesen: http://www.ftpnet.de/2016/06/29/event-7031-msexchangediagnostics-exchange-2016/ )Also öffnen wir doch mal den Performance Monitor und prüfen ob die Counter „MSExchange Global Locator Processes“ da sind. Nein, ich kann sie nicht finden, die Performance Counter sind nicht registriert. Also werde ich das manuell nachholen.

Lösung Teil2:

Zuerst die nötigen Dateien kopieren (9 Dateien):

<Installationsquelle>\ExchangeServer2016-CU1\Setup\Perf\Gls*.* kopieren nach C:\Program Files\Microsoft\Exchange Server\V15\Setup\Perf

Danach alle Performance Counter für Exchange neu einlesen (ich nutze das Script auf https://support.microsoft.com/de-de/kb/2870416:

.\perfcounter.ps1

Dieser Vorgang dauert etwa 10 – 15 Minuten und sollte ohne Fehler beendet werden (bei mir sind es 275 Perf. Counter). Hinweis: Wenn es einen Fehler mit dem InfoWorkerMultiMailboxSearchPerformanceCounters gibt, dann die InfoWorkerMultiMailboxSearchPerformanceCounters.xml mit einem Editor öffnen und „> Searches“ ersetzen mit „>Searches“. Das Leerzeichen ist zu viel.

Nach dem Serverneustart gibt es weiterhin die Events 106, aber diese haben sich geändert. Die Meldung lautet jetzt:

Performance counter updating error. Counter name is 95th Percentile Overall Latency, category name is MSExchange Global Locator Processes. Optional code: 2. Exception: The exception thrown is : System.InvalidOperationException: Instance ‚_total‘ already exists with a lifetime of Process.  It cannot be recreated or reused until it has been removed or until the process using it has exited.

Dieser Fehler liegt an .NET Framework 2.0 und ist hier beschrieben: https://support.microsoft.com/en-us/kb/971601 bzw. hier: https://social.technet.microsoft.com/Forums/office/en-US/0169ee62-bfeb-4d04-8b3d-3fa60595b1f0/after-upgrade-to-exchange-2013-cu6-application-log-flooded-with-performance-counter-updating-error?forum=exchangesvradmin

Abschluss:

Bisher habe ich noch keinen gültigen Hotfix für Server 2012 R2 gefunden, aber die Performance Counter funktionieren jetzt. Warten wir auf das nächste Cumulative Update.

P.S. Mit Exchange Server 2016 CU 2 sind die „Event 106“ Einträge nur noch Warnungen und keine Fehler mehr im Eventlog.

Installierte Software auslesen

Immer wieder passiert es und der Chef kommt zum Administrator und möchte wissen welche Software auf allen Rechnern installiert ist. Grund kann eine Lizenzzählung oder Kontrolle von unerwünschter Software sein. Natürlich gibt es tolle Software wie SCCM die das können, aber meistens Geld kosten.

Dabei gibt es verschiedene Ansätze für die Umsetzung:

wmic /output:software.htm product get Name, Version /format:htable

Das erstellt eine html Datei mit einer Liste der installierten Software. Was man auch als txt Datei Ausgeben kann:

wmic /output:C:\Software.txt product get Name, Version

Ich denke ein kleines vb Script arbeitet hier schneller und lässt sich super in ein Script während der Anmeldung verstecken:

Download des vb Scripts

Software.zip

strHost = „.“
Const HKLM = &H80000002
Set objReg = GetObject(„winmgmts://“ & strHost & _
„/root/default:StdRegProv“)
Const strBaseKey = _
„Software\Microsoft\Windows\CurrentVersion\Uninstall\“
objReg.EnumKey HKLM,strBaseKey,arrSubKeys

For Each strSubKey In arrSubKeys
intRet = objReg.GetStringValue(HKLM,strBaseKey & strSubKey,_
„DisplayName“,strValue)
If intRet <> 0 Then
intRet = objReg.GetStringValue(HKLM,strBaseKey & strSubKey,_
„QuietDisplayName“,strValue)
End If
If (strValue <> „“) and (intRet = 0) Then
set fs = CreateObject(„Scripting.FileSystemObject“)
logfile = „c:\Software.txt“
set handle = fs.OpenTextFile(logfile,8,true)
softwareName = strValue
handle.WriteLine softwareName
handle.close
End If
Next

Persönliche Benutzerordner auf mehrere Server aufteilen

Hier möchte ich mal ein paar Gedanken über die Verteilung von Benutzerordner auf mehrere Volumes/Server teilen. Mit Ordnerumleitung und servergespeicherten Profilen kann ein einzelner Fileserver schnell mal zum Bottleneck werden.

Szenario:

Wir haben viele Benutzer mit großen persönlichen Ordnern und der betreffende Fileserver ist so groß, das man Probleme beim Backup, Restore, Handling ggf. sogar bei der Performance bekommt. Auch aus Gründen des Impacts eines Serverausfall kann ein einzelner Server ein Problem sein. Genug Gründe um hier eine bessere Lösung zu implementieren.

Lösungsansatz:

Schön wäre es wenn man die persönlichen Ordner inklusive der potentiellen Ordnerumleitung auf mehrere Server verteilt. Besser wäre es wenn die Ordner für neue Benutzer automatisch erstellt werden und diese auf die Server verteilt werden.

Lösung:

Wir werden auf aktuelle Mechanismen von Server 2012 R2 zurückgreifen, um mittels DFS mehrere Benutzerordner-ablagepunkte auf verschiedene Server bzw. Volumes zu verteilen. Um die Benutzerordnerablagepunkte eindeutig zu identifizieren wird das Attribute „Pager“ des jeweiligen Benutzers gepflegt. Alternativen sind auch möglich, wobei ich davon ausgehe das heutzutage kaum mehr Pager im Einsatz sind. Zudem muss man im Active Directory für dieses Attribute keinerlei Rechte verändern, da der Benutzer den Wert für sich selber setzen darf, daß ist bei anderen Attributen nicht so und bedeutet ggf. höheren Aufwand. In diesem Beitrag möchte ich jeden Schritt erklären und beleuchten, damit potentielle Hürden wie DFS, DFS-Links und GPOs keine Relevanz mehr haben.

Anpassbar an die jeweilige Umgebung:

  • Der DFS Pfad ist anpassbar
  • Die Anzahl der Benutzerordnerablagepunkte ist anpassbar
  • Der Laufwerksbuchstabe für den persönlichen Ordner soll definierbar sein
  • neue Benutzer mit leeren Attribut müssen gleichmäßig auf alle Server verteilt werden und das Attribut muss ins AD geschrieben werden, damit immer der gleiche Server für diesen Benutzer genutzt wird
  • Kosmetik: Die Möglichkeit neu anzulegende Benutzerordner mit Großbuchstaben zu schreiben, auch wenn der SamAccountName Groß/Kleinschreibung enthält
  • Kosmetik: Die Möglichkeit den DFS Pfad beim verbundenen Laufwerk durch einen Namen zu ersetzen (z.B. Persönlicher Ordner)

Grober Ablaufplan:

  • Wichtige Werte für die Umgebung definieren
  • Shares auf den Server bereit stellen
  • DFS aufbauen, wenn nicht vorhanden
  • GPO mit dem Script erstellen/vorhandene erweitern
  • Migrationsstrategie für vorhandene Ordner

Wichtige Werte für die Umgebung definieren

In dem Script gibt es eine Sektion, in der man das Script auf die jeweilige Umgebung anpasst. Das ist wichtig, denn jede Umgebung hat andere Vorgaben. Schauen wir uns die nötigen Werte mal an.

DriveLetter

Diese Variable muss gepflegt werden und hat den Standardwert von „U:“. Wenn der Ordner zu einem anderen Laufwerksbuchstaben verbunden werden soll, dann muss genau hier Buchstabe eingetragen werden. Der Wert wird mit Doppelpunkt eingetragen.

HomeDirPath

In der Variable wird der Pfad im DFS angegeben, aber ohne ein Backslash am Ende und ohne die Nummern der DFS-Links. Wer noch nie DFS eingesetzt hat muss nicht die Mundwinkel hochziehen – DFS wird Schritt für Schritt in Teil 3 erklärt. Auch wenn wir jetzt noch nicht wissen was hier eingetragen werden soll, nach der DFS Bereitstellung in Teil 3 wissen wir das.

CountHomeStores

Die Variablen sind alle in Englisch gehalten, damit das Script auch Admins verstehen, die den deutschen nicht mächtig sind. Also diese Variable gibt an auf wie vielen Servern/Volumes zukünftig die persönlichen Ordner verteilt werden sollen. Derzeit ist es wahrscheinlich nur ein Server. Die Überlegung ist in wie viele Portionen ich die Daten auf dem einen Server aufteilen möchte. Standardwert dieser Variable ist 4, aber ggf. sind 2 für kleine oder bis zu 12 für große Unternehmen auch passend. Jeder Wert zwischen 1 und 12 ist möglich.

FoldernameUcase

Kommen wir zu etwas Kosmetik im Filesystem. Wenn diese Variable „True“ enthält dann wird bei Neuanlage eines persönlichen Ordners aus „BFischer“ „BFISCHER“ und aus „UsErNaMe67“ wird „USERNAME67“. Das soll Eingabefehler beim SamAccountName korrigieren und die Ordner vereinheitlichen. Wenn man das nicht will, dann einfach mit False deklarieren, dann wird die Funktion nicht ausgeführt. Diese Variable zieht nur bei neuen Benutzer und nicht bei bestehenden!

MappedDrivePathRename und MappedDrivePathName

Kosmetik im Explorer des Users. Die Variable MappedDrivePathRename gibt an ob das verbundene Laufwerk den DFS Pfad beinhalten soll oder ob das Laufwerk z.B. „Persönlicher Ordner“ heissen soll. Standardmäßig wird umbenannt in „Persönlicher Ordner“, wobei der Name des Laufwerks in der Variable MappedDrivePathName stehen muss. Hier kann man rumspielen, denn wird die Funktion deaktiviert, dann wird immer der DFS Pfad angezeigt.

Vorbereitung Fileserver

Fangen wir an mit der Einrichtung. Ich dokumentiere hier den Fall das wir auf einem Fileserver mehrere Volumes für die Benutzerordner nutzen wollen, alternativ kann man die Volumes auch auf verschiedenen Servern legen (große Umgebungen). Wichtig ist das die lokalen Rechte auf dem Server angepasst werden, damit Ordner automatisch angelegt werden und die Benutzerordner auch nur dem Benutzer selber gelesen und geschrieben werden können (Ausnahme Administratoren).

Zunächst habe ich 4 GPT Volumes erstellt und benannt mit Userhomes1-4 sowie einen Laufwerksbuchstaben zugewiesen. (Testumgebung daher nur 10 GB)

000257

Wir geben das Laufwerk I: frei mit den Namen „Userhomes4$“ (verstecke Freigabe) und mit den Rechten „Jeder“ hat Vollzugriff, denn die NTFS Rechte sind restriktiver. Die NTFS Rechte auf I: müssen wie folgt geändert werden:

000282

Die Rechte sollte man anpassen bevor ein Ordner auf dem Volume erstellt wurde.

000283

Ziel ist das die Berechtigungen so aussehen:

ERSTELLER-BESITZER – Vollzugriff (Anwenden auf: nur Unterordner und Dateien)

System – Vollzugriff (Anwenden auf: Diesen Ordner, Unterordner und Dateien)

Domain Admins – Vollzugriff (Anwenden auf: Diesen Ordner, Unterordner und Dateien)

Jeder – Ordner erstellen/Daten anhängen (Anwenden auf: Nur diesen Ordner)

Jeder – Ordner auflisten/Daten lesen (Anwenden auf: Nur diesen Ordner)

Jeder – Berechtigungen lesen (Anwenden auf: Nur diesen Ordner)

Jeder – Ordner durchsuchen/Datei ausführen (Anwenden auf: Nur diesen Ordner)

Quelle: http://blogs.technet.com/b/migreene/archive/2008/03/24/3019467.aspx

Die Berechtigungen werden wie folgt geändert. Alle Berechtigungen für die lokale Gruppe „Benutzer“ werden entfernt. Die Berechtigung für „Jeder“ wird bearbeitet.

000264

Erweiterte Berechtigungen anzeigen …

000265

Und das Recht „Ordner erstellen/Daten anhängen“ aktivieren und mit OK bestätigen. Sollte im Endeffekt etwa so aussehen:

000266

Dieser Vorgang wird wiederholt für die anderen Volumes mit Benutzerordnern. Danach haben wir den Part für den Fileserver fertig.

DFS einrichten

Das DFS (verteilte Dateisystem) ist gerade in großen Umgebungen unverzichtbar und eine große Hilfe. Egal ob es um Livecycle von Fileservern oder verteilen von großen Datenmengen auf verschiedene Server geht, DFS ist wichtig, damit der Pfad für die Benutzer immer gleich bleibt. Auch in unserem Fall wollen wir DFS einsetzen. Wer sich nicht damit auskennt, der sei beruhigt, ich werde Schritt für Schritt die Implementierung dokumentieren.

Domänencontroller vorbereiten

000267

000268

DFS-Namespace aktivieren (sowie der vorgeschlagenen Features) und mit Weiter akzeptieren.

000269

Das sind die Punkte die wir brauchen, also Installieren.

000270

Wenn die Installation fertig ist können wir die DFS-Verwaltung öffnen.

000271

Neuen Namespace anlegen.

000273

Der Namespaceserver ist der Server wo wir gerade die DFS Tools installiert haben. Später können wir weitere Domänencontroller als Namespaceserver hinzufügen, damit wir Redundanz schaffen für den Fall das dieser Domänencontroller ausfällt.

000286

Der Name den wir hier festlegen wird später so aussehen \\fqdn_der_Domäne\Users . Ein wichtiger Punkt verbirgt sich unter Einstellungen.

000287

Die DFS-Links, die wir gleich anlegen, werden auf dem Domänencontroller lokal abgelegt und zwar standardmäßig im Ordner C:\DFSRoots .Wir werden in unserem Beispiel keine ABE (zugriffsbasierte Aufzählung) implementieren, da das für die Benutzerordner nicht viel Sinn macht. Trotzdem ist es gut zu wissen, wo die logischen Links liegen, die auf die Fileserver zeigen.

000288

Wir nutzen den domänenbasierten Namespace. Jetzt sieht man auch den Namen unseres Namespaces, den wir in die Variable „HomeDirPath“ im Script eintragen müssen.

(Optional) zweiten Namespaceserver hinzufügen

Wenn wir mindestens zwei Domänencontroller haben bietet es sich an, zumindest einen weiteren Namespaceserver hinzuzufügen, damit die Laufwerke auch verbunden werden wenn der erste Domänencontroller ausfällt. Für kleine Umgebungen ist das optional.

000290

Namespace anwählen, auf die Karteikarte „Namespaceserver“ klicken und rechts „Namespaceserver hinzufügen“ klicken.

000291

In der folgenden Maske den zweiten Domänencontroller auswählen mit OK bestätigen schon hat man die Redundanz implementiert.

000292

Wir erstellen gleich die DFS-Links, diese werden automatisch auf beide Server gelegt. Wenn man den zweiten Namespaceserver hinzufügt nachdem man DFS-Links erstellt hat, dann muss man selber dafür sorgen dass diese auf den zweiten Server kopiert werden!

Erstellen der DFS Links

000293

Um einen DFS-Link zu erstellen wählen wir neuer Ordner.

000294

Der Name des ersten DFS-Links lautet „1“ und zeigt auf den Fileserver und der ersten versteckten Freigabe.

Tipp: Den Servernamen mit FQDN schreiben (als statt FS01 besser FS01.liesst.mit). Das löst Probleme bei Multidomänen bzw. bei Netzwerken mit verschiedenen DNS Suffixen.

000295

Das Gleiche wird im Anschluss für die restlichen DFS-Links genauso gemacht, bis wir die Zahl erreicht haben die wir möchten (in unserem Fall 4).

GPO bauen und Script hinterlegen

Logonscript Script hinterlegen

Jetzt überlegen wir eine passende Ablage für das Logonscript. Da bietet sich natürlich das NETLOGON an, weil das zwischen den Domänencontroller repliziert wird.

000298

Also auf dem Domänencontroller im Explorer C:\Windows\SYSVOL\domain\scripts eingeben und einen neuen Ordner erstellen, ich nenne ihn „Logonscript“.

000299

Da hinein legen wir die beiden Dateien für das Logonscript.

000300

Inhalt der Logonscript.cmd

Die Variable %Logonserver% wurde bewusst genutzt. Würden wir hier den FQDN der Domäne eintragen, dann müssen wir per GPO zusätzlich dafür sorgen, dass der FQDN der Domäne in den vertrauenswürdigen Seiten des Internet Explorer aller Clients eingetragen wird. Sicherer ist hier die Nutzung der Variable %Logonserver%

Anpassen des Scriptes

Jetzt passen wir das Script auf die jeweilige Umgebung an. Als Laufwerksbuchstaben möchte ich gern U: haben, also:

DriveLetter = „U:“

Der DFS Pfad in meinen Fall lautet:

HomeDirPath = „\\liesst.mit\Users“

Auf dem Fileserver habe ich 4 Volumes, 4 Freigaben und somit 4 DFS-Links erstellt:

CountHomeStores = 4

Jetzt die optionalen Einstellungen. Ich möchte das die Namen der Benutzer auf dem Fileserver groß geschrieben werden, also:

FoldernameUcase = „True“

Und das U: Laufwerk soll für den Benutzer umbenannt werden in Persönlicher Ordner, damit der DFS Pfad verschwindet:

MappedDrivePathRename = „True“

MappedDrivePathName = „Persönlicher Ordner“

Die letzte optionale Einstellung ist der Ablageort der Logdatei. Die würde ich gern in das Temp Verzeichnis schreiben. Die Datei wird jedesmal überschrieben und ist wenige kb groß.

Logfile = WshSysEnv(„TEMP“) & „\“ & „logon-results.txt“

Wer das nicht will – einfach auskommentieren.

Tipp: Wenn das Speichern des Scripts nicht funktioniert im Vorwege den Namen auf Logon2.vbs ändern, das Script bearbeiten und Speichern als Logon.vbs , alternativ kann man das Script unter C:\Temp anpassen und danach in den Originalordner kopieren.

GPO erstellen

000301

Gruppenrichtlinienverwaltung öffnen

000302

Neue GPO erstellen

000303

Und einen Namen geben.

000304

Unter Richtlinien\Windows-Einstellungen\Skripts ein Anmeldescript hinterlegen

000305

\\fqdn_der_Domäne\NETLOGON\Logonscript finden wir unser Script und wählen die cmd Datei aus.

000306

2 Mal mit OK bestätigen.

Optional kann in der gleichen GPO noch ein weiterer Wert definiert werden.

000308

Unter Computerkonfiguration\Richtlinien\Administrative Vorlagen\System\Gruppenrichtlinie sollte man den Punkt „Anmeldeskriptverzögerung konfigurieren“ (engl. Configure Logon Script Delay) und dort den Wert „0“ eintragen. Hintergrund: Bei Windows 8.1 kann es dazu kommen dass das Logonscript erst Minuten nach der Anmeldung abgearbeitet wird. Durch setzen des Wertes auf „0“ wird das Script sofort abgearbeitet. Siehe KB2895815 von Microsoft.

000310

Final muss nun noch die Gruppenrichtlinie in der Domäne bzw. an eine OU verknüpft werden.

Migrationsstrategie für vorhandene Ordner

Da in den wenigsten Fällen grüne Wiese existiert muss man sich Gedanken machen wie man die Ordner von dem alten Server auf die neuen Server bekommt und dabei so wenig wie möglich Unterbrechung gibt.

000312

Man kann die neue GPO einstellen, dass sie nur von Mitgliedern einer Active Directory Gruppe übernommen wird. Somit gilt die GPO zuerst für niemanden. Wenn man nun den Ordner eines Benutzers kopiert hat, dann setzt man das Attribut „Pager“ für diesen Benutzer und nimmt ihn in die neue Gruppe auf. Auf dem alten Server nimmt man die Rechte für diesen User für seinen alten Ordner weg. Wenn der Benutzer das nächste Mal sich anmeldet, dann bekommt er das neue Logonscript und somit sein Laufwerk verbunden mit dem neuen Server. Somit kann man die Migration schrittweise und kontrolliert vollzogen werden.

Benutzer die neu angelegt werden müssten sofort in die neue AD-Gruppe aufgenommen werden, damit das Benutzer Attribute automatisch generiert wird und der Ordner auf dem Server angelegt wird.

Wenn die Ordner aller Benutzer migriert sind, kann man die Zuweisung der GPO wieder für alle Benutzer zulassen und die AD-Gruppe ist nicht mehr nötig.

Troubleshooting

Standardmäßig wird ein Log in den Ordner der lokalen Variable %Temp% abgelegt. Wenn das Laufwerk nicht verbunden wird, ist das der erste Anlaufpunkt. Standardmäßig findet man das Log unter C:\Users\<Benutzername>\AppData\Local\Temp

000313

Also %temp% in der Adresszeile eingeben und mit Enter bestätigen.

000314

Schon kann man das Log sich anschauen.

000315

Einige Standardfehler habe ich versucht schon im Script abzufangen.

Unzureichende Rechte auf dem persönlichen Ordner

Fehlermeldung im Log:

-2147024891 Hat der Benutzer TESTER02 wirklich volle Rechte auf den Ordner \\liesst.mit\Users\2\TESTER02 ?

000316

Dieser Punkt wird von Script geprüft und ins Log geschrieben. Dabei tritt ein Timeout ein was die Verarbeitung des Scriptes verzögert, aber man kann den Fehler sofort lesen.

Abhilfe:

Auf dem Fileserver die Rechte des Ordners prüfen. Ggf. wurden die Rechte nicht korrekt neu gesetzt nachdem der Ordner von einem anderen Server kopiert wurde.

Wert des Attributes Pager für den Benutzer ist nicht korrekt

000317

Wenn der Wert des Pager Attributes zu groß oder zu klein ist, dann fängt das Script diesen Fehler ab und generiert eine Fehlermeldung für den Benutzer.

Abhilfe:

Prüfen ob der Ordner auf dem Fileserver schon vorhanden ist und die korrekte Zahl in das Attribute eintragen.

Im Benutzerobjekt ist der Wert Basisordner verbinden gesetzt

Fehlermeldung im Log:

— Achtung! —

Wenn das Laufwerk nicht mehr verbunden ist liegt das ggf. daran, das bei diesem Benutzer im AD

auf der Karteikarte Profil der Punkt Basisordner verbunden wird mit …

000319

Abhilfe:

Im AD Benutzerobjekt prüfen ob die Konfiguration des Basisordners aktiviert ist und deaktivieren.

EnableLinkedConnections nicht vorhanden

Fehlermeldung im Log:

Key HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLinkedConnections nicht vorhanden!

000320

Wenn UAC aktiviert ist kann es sein, dass das Laufwerk nicht korrekt verbunden wird. Dann sollte man EnableLinkedConnections mit dem Wert 1 in die Registry eintragen. Siehe: https://technet.microsoft.com/de-de/library/ee844140%28v=ws.10%29.aspx

Anregungen zum Erweitern des Scriptes

Hier sind ein paar Punkte aufgezählt, wie man das Script auf persönliche Wünsche erweitern kann. Diese sind aber nicht allgemein und deswegen nicht implementiert.

  • Das Script kann man dazu benutzen auch weitere Laufwerke zu verbinden.
  • Man kann das Script erweitern, so dass der Administrator eine E-Mail erhält, wenn ein Fehler auftritt.
  • Man kann das Script erweitern, so dass die Migration der Daten vom alten Server auf den neuen Server vollzogen wird. Bedeutet aber Wartezeit bei der Anmeldung oder zumindest eine Info an den User, dass die Daten im Hintergrund migriert werden.
  • Statt DFS kann man auch dediziert eine Reihe von Ablageorten auf verschiedenen Servern festlegen – ich finde DFS schicker.

Getestet auf: Server 2008 R2 und höher, sowie Windows 7 und höher

Download des vb Scripts

Logonscript

Inhalt der Loginscript.cmd

cscript //nologo %Logonserver%\NETLOGON\Logonscript\Logon.vbs

Inhalt der Logon.vbs

‚~~[author]~~
‚Daniel Schober
‚~~[/author]~~

‚~~[emailAddress]~~
‚script (at) ftpnet (dot)de
‚~~[/emailAddress]~~

‚~~[scriptType]~~
‚vbscript
‚~~[/scriptType]~~

‚~~[subType]~~
‚SystemAdministration
‚~~[/subType]~~

‚~~[keywords]~~
‚windows, microsoft, active directory, attribute, schema, logon script, dfs
‚~~[/keywords]~~

‚ Das Script verbindet das persönliche Laufwerk eines Benutzers auf einem bestimmten Laufwerksbuchstaben. Wenn noch kein
‚ persönlicher Ordner existiert, dann wird einer angelegt. Dabei wird jeden Monat ein anderer Server zur Neuanlage benutzt.
‚ Zudem findet eine Plausibelitätsprüfung des Attributes statt.

‚*******************************************************************************
Option Explicit

Dim objRootDSE, objDNSDomain, objFso, objShell, objDrives, objLog
Dim objUser, objUserID, objSysInfo, objNetwork, objUsername, objHomeDir
Dim DriveLetter, HomeDirPath, FoldernameUcase, TimeStart, ScriptDuration
Dim CountHomeStores, UserHomeID, i, Logfile, WshSysEnv, WshShell
Dim MappedDrivePathRename, MappedDrivePathName, Regvalue, errString

‚ Starte den Timer

TimeStart = Timer

‚ Verbindung mit dem Active Directory

Set objRootDSE = GetObject(„LDAP://RootDSE“)
objDNSDomain = objRootDSE.Get(„DefaultNamingContext“)

‚*******************************************************************************
‚ Trage Accountinformationen zusammen

Set objNetwork = CreateObject(„WScript.Network“)
Set objSysInfo = CreateObject(„ADSystemInfo“)
Set objUser = GetObject(„LDAP://“ & objSysInfo.UserName)
objUsername = objUser.sAMAccountName
objHomeDir = objUser.homeDirectory

Set objShell = CreateObject(„Shell.Application“)
Set objFso = CreateObject(„Scripting.FileSystemObject“)
Set WshShell = WScript.CreateObject(„WScript.Shell“)
Set WshSysEnv = WshShell.Environment(„PROCESS“)

‚*******************************************************************************
‚ Das ist der Bereich, der auf die jeweilige Umgebung angepasst werden muss

‚ Welcher Laufwerksbuchstabe soll für das Benutzerverzeichnis gesetzt werden?

DriveLetter = „U:“

‚ Wie lautet der Pfad zum DFS? (ohne „\“ am Ende!)
‚ Bsp: \\dfs-path\folder
‚ Bsp: \\mydomain.local\Global\User

HomeDirPath = „\\liesst.mit\Users“

‚ Wie viele verschiedene Benutzerordnerablagepunkte soll es geben?
‚ Diese Zahl muss der Anzahl der erstellten DFS Links entsprechen
‚ Zahl zwischen 1 – 12

CountHomeStores = 4

‚ Soll der persönliche Ordnername eines neuen Benutzers groß geschrieben werden (bei Neuanlage)?
‚ Hintergrund: Der Samaccountname könnte teils groß teils klein geschrieben werden. Hiermit können die Ordnernamen angepasst werden.
‚ Kosmetischer Faktor – für die Funktion des Scripts unwichtig
‚ Entweder True oder False (False schaltet die Funktion ab)

FoldernameUcase = „True“

‚ Soll der Netzwerkpfad des gemappten Benutzerlaufwerks umbenannt werden, damit der kryptische Name versteckt wird?
‚ Kosmetischer Faktor – für die Funktion des Scripts unwichtig
‚ Entweder True oder False (False schaltet die Funktion ab)

MappedDrivePathRename = „True“
MappedDrivePathName = „Persönlicher Ordner“

‚ Wohin soll das Logfile lokal geschrieben werden?
‚ Das Logfile wird jedesmal überschrieben

Logfile = WshSysEnv(„TEMP“) & „\“ & „logon-results.txt“

‚ End of customization.
‚*******************************************************************************
‚*******************************************************************************
Set objLog = objFso.CreateTextFile(Logfile, True)
objLog.WriteLine „——————————————————————“
objLog.WriteLine „Start des Scripts: “ & (cstr(Now))
objLog.WriteLine „Benutzerobjekt = “ & objSysInfo.UserName
objLog.WriteLine „SamAccountName = “ & objUser.sAMAccountName
objLog.WriteLine „Konfigurierter Laufwerksbuchstabe = “ & DriveLetter
objLog.WriteLine „Konfigurierter DFS Pfad = “ & HomeDirPath
objLog.WriteLine „Anzahl konfigurierter Benutzerordnerablagepunkte ist “ & CountHomeStores & „. Daraus ergeben sich folgende DFS-Links:“
For i = 1 To CountHomeStores
objLog.WriteLine HomeDirPath & „\“ & i
Next
‚*******************************************************************************
‚ Lese das Attribute aus dem Active Directory
‚ Ich habe mich für den Wert Pager entschieden, da dieser heute kaum noch genutzt wird
‚ wird ein alternatives Attribute genutzt, dann im Script „pager“ durch das neue Attribut ersetzen
‚ Achtung bei Custom Attributen! Rechte setzen, damit der Benutzer diesen Wert ändern darf!

UserHomeID = objUser.pager
objLog.WriteLine „Ausgelesender Wert für Attribut pager = “ & UserHomeID

‚*******************************************************************************
‚ Prüfe ob das Attribute leer ist
‚ Wenn ja, dann hole den aktuellen Monat als Zahl
‚ Ist die Zahl größer als die Anzahl der Benutzerordnerablagepunkte, dann wird die Zahl um den
‚ Wert der Benutzerordnerablagepunkte subtrahiert, bis die Zahl kleiner oder gleich ist
‚ Zudem wird der neue Wert dann ins AD geschrieben
‚ Das wird gemacht damit neue Benutzer jeden Monat auf einen anderen Server verteilt werden

If (IsEmpty(UserHomeID)) Then
UserHomeID = Month(Now)
objLog.WriteLine „Das Attribut pager für den User “ & objUsername & “ war im Active Directory nicht gepflegt.“
objLog.WriteLine „Die Nummer des aktuellen Monats = “ & Month(Now) & „.“
Do While UserHomeID+0 > CountHomeStores+0
objLog.WriteLine „Der Wert “ & UserHomeID & “ ist zu groß und wird subtrahiert mit “ & CountHomeStores
UserHomeID = UserHomeID – CountHomeStores
Loop
‚ Schreibe den neuen Wert in das Attribute des Users

objUser.Put „pager“, UserHomeID
objUser.SetInfo
objLog.WriteLine „Schreibe den neuen Wert “ & UserHomeID & “ für das Attribute pager ins AD.“
End If

‚*******************************************************************************
‚ Prüfe ob der Wert im Active Directory valide ist

If UserHomeID+0 > CountHomeStores+0 Then
MsgBox „Bitte informieren Sie Ihren Administrator. Der Wert für pager des Benutzers “ & objUsername & “ ist “ & UserHomeID & „. Die konfigurierte Anzahl der Benutzerordnerablagepunkte ist “ & CountHomeStores & „.“,VBOKOnly,“Benutzerlaufwerk “ & DriveLetter & “ konnte nicht verbunden werden!“
‚ MsgBox „Please contact your admin. The value for pager is “ & UserHomeID & “ for user “ & objUsername & “ & „. Configured distributed home shares is “ & CountHomeStores & „.“,VBOKOnly,“Drive “ & DriveLetter & “ couldn`t be mapped!“
ElseIf UserHomeID < 1 Then
MsgBox „Bitte informieren Sie Ihren Administrator. Der Wert für pager des Benutzers “ & objUsername & “ ist “ & UserHomeID & „. Dieser Wert muss größer 0 sein, jedoch maximal “ & CountHomeStores & „.“,VBOKOnly,“Benutzerlaufwerk “ & DriveLetter & „: konnte nicht verbunden werden!“
‚ MsgBox „Please contact your admin. The value for pager is “ & UserHomeID & “ for user “ & objUsername & „. The value must be at least 1, but not greater than “ & CountHomeStores & „.“,VBOKOnly,“Drive “ & DriveLetter & “ couldn`t be mapped!“
End If

‚*******************************************************************************
‚ Schreibe den Benutzernamen mit Großbuchstaben, wenn gewünscht.

If FoldernameUcase = „True“ Then
objUsername = ucase(objUsername)
objLog.WriteLine „Ordnernamen umgewandelt in Grossbuchstaben -> “ & objUsername
End If

‚*******************************************************************************
‚ Prüfe ob der persönliche Ordner vorhanden ist und erstelle ihn neu wenn nötig.

objLog.WriteLine „Prüfe ob der Pfad existiert: “ & HomeDirPath & „\“ & UserHomeID & „\“ & objUsername
If objFso.Folderexists(HomeDirPath & „\“ & UserHomeID & „\“ & objUsername) = false then
objFso.CreateFolder(HomeDirPath & „\“ & UserHomeID & „\“ & objUsername)
objLog.WriteLine „Ordner existiert nicht. Erstelle den Ordner “ & HomeDirPath & „\“ & UserHomeID & „\“ & objUsername
Else objLog.WriteLine „Pfad existiert. Ordner muss nicht erstellt werden.“
End if

‚*******************************************************************************
‚ Trenne das Benutzerlaufwerk (wenn verbunden) und verbinde es neu.

If(objFso.DriveExists(DriveLetter)) Then
objNetwork.RemoveNetworkDrive DriveLetter, True, True
objLog.WriteLine „Laufwerk “ & DriveLetter & “ war bereits verbunden und wurde getrennt.“
End If

wscript.sleep 100
objLog.WriteLine „Versuche Laufwerk “ & DriveLetter & “ mit “ & HomeDirPath & „\“ & UserHomeID & „\“ & objUsername & “ zu verbinden.“
On Error resume Next
objNetwork.MapNetworkDrive DriveLetter, HomeDirPath & „\“ & UserHomeID & „\“ & objUsername
If Err <> 0 then
Select case Err.Number
case -2147024891
objLog.WriteLine err.Number & “ Hat der Benutzer “ & objUsername & “ wirklich volle Rechte auf den Ordner “ & HomeDirPath & „\“ & UserHomeID & „\“ & objUsername & “ ?“
case else
objLog.WriteLine „Fehler “ & err.Number & “ –> “ & Err.Description
End Select
End If
‚*******************************************************************************
‚ Benenne den Netzwerkpfad des gemappten Benutzerlaufwerks um, wenn gewünscht.

If MappedDrivePathRename = „True“ Then
objShell.NameSpace(DriveLetter).Self.Name = MappedDrivePathName
Else
objShell.NameSpace(DriveLetter).Self.Name = HomeDirPath & „\“ & UserHomeID
End If

objLog.WriteLine „Folgende Netzlaufwerke sind an diesem Client verbunden:“
Set objDrives = objNetwork.EnumNetworkDrives
For i = 0 to objDrives.Count-1 Step 2
objLog.WriteLine objDrives.Item(i) & vbTab & objDrives.Item (i + 1)
Next

‚*******************************************************************************
‚ Fange Standardfehler ab: Basisordner hat einen Wert im AD

If Not (IsEmpty(objHomeDir)) Then
objLog.WriteLine „— Achtung! —“
objLog.WriteLine „Wenn das Laufwerk nicht mehr verbunden ist liegt das ggf. daran, das bei diesem Benutzer im AD“
objLog.WriteLine „auf der Karteikarte Profil der Punkt Basisordner verbunden wird mit “ & objHomeDir
End If

‚*******************************************************************************
‚ Fange Standardfehler ab (Netzlaufwerk ist verschwunden, wenn UAC aktiviert ist)
‚ https://technet.microsoft.com/de-de/library/ee844140%28v=ws.10%29.aspx

objLog.WriteLine „“
If RegExists(„HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLinkedConnections“) Then
Regvalue = WshShell.RegRead(„HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLinkedConnections“)
If Regvalue = 1 Then
objLog.WriteLine „Key HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLinkedConnections vorhanden.“
Else
objLog.WriteLine „Key EnableLinkedConnections vorhanden – Wert ist aber nicht = 1 !“
objLog.WriteLine „HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\“
objLog.WriteLine „RegDWORD EnableLinkedConnections=1“
objLog.WriteLine „siehe https://technet.microsoft.com/de-de/library/ee844140%28v=ws.10%29.aspx“
End If
Else
objLog.WriteLine „Key HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLinkedConnections nicht vorhanden!“
objLog.WriteLine „Wenn das Laufwerk “ & DriveLetter & “ nicht mehr verfügbar ist und UAC aktiviert ist bitte folgenden Regkey setzen und“
objLog.WriteLine „Computer neu starten: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\“
objLog.WriteLine „RegDWORD EnableLinkedConnections=1“
objLog.WriteLine „siehe https://technet.microsoft.com/de-de/library/ee844140%28v=ws.10%29.aspx“
End If
objLog.WriteLine „“

Function RegExists(regPath)

On Error Resume Next
RegExists = False
If (Right(regPath, 1) <> „\“) Then
Regvalue = WshShell.RegRead(regPath)
If (Err.Number=0) Then RegExists = True
Else
Regvalue = WshShell.RegRead(„HKLM\Nothing\“)
errString = Replace(Err.Description, „““HKLM\Nothing\““.“, „“ )
Regvalue = WshShell.RegRead(regPath)
If (Err.Number=0) Then
RegExists = True
Else
If Replace(Err.Description, „“““ & regPath & „““.“, „“ ) <> errString Then
RegExists = True
End If
End If
End If

Set WshShell = Nothing
On Error Goto 0
End Function

‚*******************************************************************************
‚ Berechne die Dauer, die das Script gebraucht hat

ScriptDuration = Int((Timer – TimeStart) * 1000)
objLog.WriteLine „Ende des Scripts. Die Scriptverarbeitung hat “ & ScriptDuration & “ Millisekunden gedauert.“
objLog.WriteLine „——————————————————————“

‚*******************************************************************************
‚ Schliesse das Log und beende das Script.

objLog.Close
set objNetwork=nothing
WScript.Quit