Powershell und NTFS

Es geht wieder einmal um meine beiden Lieblingsthemen Microsoft und BlueArc. Seit nunmehr einem Jahr liegen unsere Daten auf dem BlueArc Mercury System und werden von dort via NFS zur Verfügung gestellt. Für die Windowsclients gibt bzw. gab es bisher zwei BSD-Samba Server die eben diese NFS-Freigabe weitergeleitet haben. Natürlich beherrscht das Mercury auch CIFS und der Zwischenschritt über Samba war noch von dem Vorgängersystem. Wie auch immer, sollen die Verzeichnisse nun direkt vom Mercury kommen sowohl für CIFS wie auch NFS für unixbasierte Clients. Das ist in der Theorie kein Problem und steht auch schön im Hochglanzprospekt beschrieben. In der Praxis funktioniert das auch für ein frisches Dateisystem mehr oder minder problemlos, sofern man dem NFS-Teil einfach sagt er solle sämtliche Rechteänderungen einfach in die Tonne treten und die NTFS-Vorgaben umsetzen, ansonsten kann es schon mal sein das man sich mit chmod/chgrp/chown ein paar Zugriffsrechte zerlegt, teilweise auch rekursiv, was man vermeiden möchte.

Gut, wir haben nur halt kein frisches Dateisystem sondern 35.000 Accounts mit 36.000.000 Dateien. Mein Vorschlag zu behaupten der Plattenstappel wäre abgebrannt und man hätte auch kein Backup um es wieder herzustellen damit man bei Null anfangen kann, wurde leider nicht angenommen.

Zusätzlich sollte es noch einige Umstrukturierungen im Active Directory geben, genauer gesagt eine Reorganisation der Nutzerobjekte in neue OUs.

Damit verbunden dann auch gleich eine neue Primärgruppe der Nutzer, womit sich auch die Gruppe unter Unix ändert.

Da unsere Nutzerobjekte alle vom Novell eDirectory verwaltet werden, muss man da nur ein paar Kleinigkeiten ändern und für Neuanlagen hat man das dann erledigt. Die Bestandskunden möchte man aber dann doch aus Perfomancegründen lieber direkt im AD ändern, da ich inzwischen die Powershell ja ganz nützlich finde, war das auch relativ einfach und sieht so aus:

$Students = "ou=Hier Sind Alle Nutzer, dc=Objekte, dc=Unserer, dc=Domäne"
$GidNumber = 1000513
$Filer = "FullQualifiedDomainName-unseres-Mercury"
$OldOU = @("ou=A-L", "ou=M-Z" )

foreach ($CurrentOU in $OldOU)
{
    write-host "Moving Users from $CurrentOU";
    $SearchBase = "LDAP://$env:computername/$CurrentOU,$Students"
    write-host $SearchBase
    $adsi = [ADSI]$SearchBase

    foreach($CurrentAccount in $adsi.Children)
    {
        if($CurrentAccount.ObjectCategory -like "CN=Person*")
        {
            $FC = ([String]$CurrentAccount.SAMAccountName).Substring(0,1)
            $NewOU = "OU=$FC, $Students"
            $Name = $CurrentAccount.SAMAccountName
            $CurrentAccount.ProfilePath = "$Filerhomeusers$NameProfile"
            $CurrentAccount.UnixHomeDirectory = "/home/users/$Name"
            $CurrentAccount.GidNumber = $GidNumber
            write-Host "Moving " $CurrentAccount.SAMAccountName " To " $NewOU "New Profile: " $CurrentAccount.ProfilePath " New UnixHomedir: " $CurrentAccount.UnixHomeDirectory >> Move.log

            $CurrentAccount.SetInfo()
            dsmove $CurrentAccount.distinguishedName -newParent $NewOu
        }
        else
        {
            write-host "Skipping Object " $CurrentAccount.distinguishedName >> Move.log
        }
    }
}

Bisher waren die Nutzer je nach Nachname in die OU=A-L bzw. M-Z einsortiert, jetzt werden sie in eine OU mit dem ersten Buchstaben der UID eingegliedert. Damit haben nun also Nutzerobjekte ein neues Zuhause, einen neuen Windowsprofilpfad, eine Neue gidNumber und ein neues UnixHomeDirectory. Problem eins gelöst 😉

Problem Nummer Zwei war dann etwas hartnäckiger, wie erstellt man für dieses vollgemüllte Dateisystem nun sauberer ACLs? Auch da fangen wir erstmal klein an, erstmal setzen wir die Primarygroup um und weil es dafür auch chgrp tut, anstatt das irgendwo unter Windows zusuchen startet man einfach mal “chgrp -R 1000513 /home” im Screen und wartet dann halt 3 Tage bis das fertig ist -

Währenddessen überlegt man sich dann wie man neue Verzeichniss über die Powershell mit entsprechenden ACLs anlegt und das sieht dann so aus:

$Acl = new-object System.Security.AccessControl.DirectorySecurity
$Acl.SetAccessRuleProtection($false, $true)
$Account = New-Object System.Security.Principal.NTAccount("Domäne", $UserName)
$AccountSID = try { $Account.Translate([System.Security.Principal.SecurityIdentifier]) } catch { Write "Nutzer $UserName nicht gefunden"; exit 1 }
$Permissions = [System.Security.AccessControl.FilesystemRights]"FullControl"
$InheritFlag = [System.Security.AccessControl.InheritanceFlags]::ObjectInherit -bor [System.Security.AccessControl.InheritanceFlags]::ContainerInherit
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
$AclOwner = new-object System.Security.AccessControl.FileSystemAccessRule($AccountSID, "FullControl", $InheritFlag, $PropagationFlag, "Allow")
$Group = new-object System.Security.Principal.NTAccount("Domäne", "Domain Users")
$GroupSD = $Group.translate([System.Security.Principal.SecurityIdentifier])
$AclDA = new-object System.Security.AccessControl.FileSystemAccessRule("DomäneDomain Admins", "FullControl", $InheritFlag, $PropagationFlag, "Allow")
$AclEA = new-object System.Security.AccessControl.FileSystemAccessRule("DomainUberadmins", "FullControl", $InheritFlag, $PropagationFlag, "Allow")
$AclRO = new-object System.Security.AccessControl.FileSystemAccessRule("DomäneBackupnutzer", "ReadAndExecute", $InheritFlag, $PropagationFlag, "Allow")
foreach($CurrentRule in $AclOwner, $AclDA, $AclEA,  $AclRO)
{
    $Acl.SetAccessRule($CurrentRule)
}
$Acl.SetOwner($AccountSID)
$Acl.SetGroup($GroupSD)
if (!$(Test-Path $Homedir))
{
    try { New-Item -ItemType Directory -Path $Homedir -ea Stop | out-null } catch { Write "Konnte $Homedir nicht anlegen" ; exit 1 }
    try { Set-Acl -Path $Homedir -AclObject $Acl -ea Stop } catch { Write "Konnte ACLs nicht auf $Homedir anwenden"; exit 1 }
}
else
{
    Write "Verzeichnis $Homedir bereits vorhanden"
}

Damit wird ein neuer Securitydescriptor erzeugt mit Full-Control-Rechten für den Besitzer, Domainadmins und Admins der Admins sowie als Veranschaulichung Read&Only für eine Nutzer unter dem das Tapebackup laufen könnte. Dazu noch Owner und Groupinformation geändert, neues Verzeichnis erstellen, die ACL da drüber bügeln und schon haben wir ein schönes neues Homeverzeichnis mit feinen vererbaren NTFS-Regeln.

Problem Drei wie bekommt man diese Regeln jetzt in das bestehende Dateisystem? Tja und hier hab ich dann einfach mal nach 3 Tagen keinen Bock mehr gehabt -.-

Setzt man diese Regel nämlich auf ein bestehendes Verzeichnis, dann vererbt er zwar den Owner auf sämtliche Children, die ACL aber aus einem mir unerfindlichen Grund nicht. In der GUI kann man dann einen Haken setzen “Apply for all Children bla” und angeblich erwischt man den auch über irgendein WMI-Object, aber anscheinend hat das noch niemand in der Realität probiert. “Best-Practice” ist ein:

get-chiditems $Homedir | for-each { set-acl -path $_.fullname }
oder ähnlich, das dauert dann halt leider auch nur etwa 5 Minuten pro Account, statt der 5 Sekunden die das Häckchen in der GUI braucht, naja dafür muss ich nicht 35 tausendmal auf OK klicken.