Hallo, hier mal wieder Andy mit einem Powershell Script Thema. Es ist Wiesnzeit also eigentlich genau der richtige Zeitpunkt um sich bei seinen Anwender mal wieder beliebt zu machen.
Wer kennt das nicht - die Benutzerverzeichnisse werden auf einem Server angelegt, der unendlich viel Platz besitzt - doch nach einer gewissen Zeit ist aus dem unendlichen vielen Platz eine endliche Festplattenkapazität geworden. Also schnell die Daten von dem Server auf den neuen Server mit unendlich viel Platz kopieren. Nach dem kopieren noch im Active Directory das Benutzerverzeichnis ändern und beim nächsten Login zeigt der Laufwerksbuchstabe auf den neuen Server - gerettet und ab auf die Wiesn!?

Wäre die Welt nur so einfach, könnten wir wahrscheinlich heute schon bis zum Mars fliegen. Denn leider gibt es Anwendungen (insbesondere ein Mail Programm mit Aussicht :) ) die sind so clever und sagen sich ein Netzwerklaufwerks Buchstabe kann sich ändern, ich löse lieber den Servernamen und den Pfad in einen UNC Pfad auf und verlass mich nicht auf Laufwerksbuchstaben. Somit kann ich als Applikation immer auf einen Pfad zugreifen. Diese Information über schreibe ich zu Sicherheit bei der ersten Benutzung in die Registry für den Benutzer. Immer dann, wenn der Benutzer meine Applikation startet, greift die Applikation über den UNC Namen auf die Daten zu, unabhängig von irgendwelchen Laufwerksbuchstaben – nur das geht nach obigem Serverumzug dann in die Hose.

Ja so misstrauisch gegen Laufwerksbuchstaben kann man als Applikation sein …. muss man aber nicht. Aber was tun, wenn meine Applikationen die UNC Namen des Benutzerverzeichnisses verwendet und keine Laufwerksbuchstaben. Der Königsweg ist mit Sicherheit der Einsatz vom Distributed File System. Hierbei können die Daten im Hintergrund von einem Server auf den nächsten verschoben werden ohne dass sich der Pfad für die Benutzer ändert.

Aber was macht man wenn kein DFS vorhanden ist oder nicht eingesetzt werden kann? Man ändert den Pfad des Benutzerverzeichnis und sagt dem Benutzer: Öffne den Regedit und such nach dem alten Pfad und schreib dafür den neuen Pfad rein. Das ist für den Einzelnen teilweise recht umständlich - und schon ist man mit seiner Maß alleine auf der Wiesn.

Man kann die gesamte Sache natürlich auch automatisieren. Wie das heute üblich ist habe ich dazu die PowerShell verwendet. Hierbei erst mal einen herzlichen Dank an Jason und seinen Blog
http://blog.codeassassin.com/2007/08/02/powershell-registry-find-and-replace/
der eine schöne Routine zum Suchen und Ersetzten in der Registry geschrieben hat.

Jetzt muss der Anwender nur noch ein PowerShell Script mit dem alten und dem neuen UNC Pfad starten - und schon sind wir schon wieder alleine auf der Wiesn.

Also habe ich diese Funktionen genommen und ein wenig erweitert. Beim ersten Aufruf des Script wird zuerst einmal geprüft ob es den Pfad HKCU\Software\Microsoft\KonwnUserHome gibt. Ist der Pfad nicht vorhanden bzw. kein UNC Pfad wird im AD nach dem Benutzerpfad gesucht und in diesem Key eingetragen.

Wird das Script erneut aufgerufen, vergleichen wir alle Registry Werte mit dem aktuellen Wert für den UNC Pfad, der in der Umgebungsvariable HomeShare eingetragen ist. Stimmen beide überein, lassen wir es wie es ist. Ist dies nicht der Fall, ersetzen wir jeweils die „alten“ Werte in der Registry durch den neuen AD Wert - und gehen dann endlich mit glücklichen Anwendern auf die Wiesn (natürlich nicht, ohne das Script vorher in einer Testumgebung geprüft zu haben).
Hier nun das Powershell Script dazu, welches man dann nur in die Shell kopieren muß:

function Find-RegistryValue (
[string] $seek = $(throw “seek required.”),
[System.Management.Automation.PathInfo] $regpath = (Get-Location) ) {
   $seek = $seek -replace "\\", "\\"
   if ($regpath.Provider.Name -ne “Registry”) { throw “regpath required.” }
   $keys = @(Get-Item $regpath -ErrorAction SilentlyContinue) `
   + @(Get-ChildItem -recurse $regpath -ErrorAction SilentlyContinue);
   $results = @();
   foreach ($key in $keys) {
      foreach ($vname in $key.GetValueNames()) {
         $val = $key.GetValue($vname);
         if ($val -match $seek) {
            $r = @{};
            $r.Key = $key;
            $r.ValueName = $vname;
            $r.Value = $val;
            $results += $r;
         }
      }
   }
$results;
}

function Replace-RegistryValue (
[string] $seek = $(throw "seek required."),
[string] $swap = $(throw "swap required."),
[System.Management.Automation.PathInfo] $regpath = (Get-Location) ) {
   $find = Find-RegistryValue -seek $seek -regpath $regpath;
   $results = @();
   $seek = $seek -replace "\\", "\\"
   foreach ($target in $find) {
      $nval = $target.Value -replace $seek, $swap;
      $r = @{};
      $r.Key = $target.Key;
      $r.ValueName = $target.ValueName;
      $r.OldValue = $target.Value;
      $r.NewValue = $nval;
      $results += $r;
      $wKey = (Get-Item $r.Key.PSParentPath).OpenSubKey($r.Key.PSChildName, "True");
      $wKey.SetValue($target.ValueName, $nval);
   }
$results;
}

Set-Location HKCU:
[string] $KnownPath
[string] $CurrPath
$KnownPath = (Get-ItemProperty "HKCU:\software\Microsoft").KnownUserHome
$CurrPath = (Get-ChildItem "Env:\HomeShare").Value
write-host "KnownPath" $KnownPath
write-host "CurrPath" $CurrPath
if (![string]::IsNullOrEmpty($CurrPath))
{
   if ([string]::IsNullOrEmpty($KnownPath)) {
      Set-ItemProperty -path "HKCU:\software\Microsoft" -name "KnownuserHome" -value $CurrPath
   }
   else {
      if ([string]::Compare($CurrPath,$KnownPath,$False)) {
         Write-Host "Replace home unc path"
         Replace-RegistryValue $KnownPath $CurrPath
      }
   }
}

Oans-zwoa-gsuffa :)
AndyL