3 Datei- und Verzeichnisberechtigungen

Jetzt kommt vielleicht der Teil, an den man als erstes denkt, wenn die Begriffe "Skripting" und "Filesystem" gemeinsam auftauchen. 

Wie kann man Berechtigungen auf Ordner und Dateien auslesen oder verändern? Die Programmierung ist meiner Meinung gar nicht so arg schwierig, die Theorie des Berechtigungssystems des NTFS-Filesystems ist eher die Herausforderung. Andererseits stellt die MicrosoftGUI, die in den nachfolgenden Kapiteln immer wieder auftaucht, ein grafisches Hilfsmittel bereit, mit dem sich alle programmatischen Aktionen leicht nachvollzuziehen lassen. 

Wenn die NTFS-Theorie zu komplex wird -bei Eigenschaften wie IsInherited, InheritanceFlags, PropagationFlags kann man schon den Überblick verlieren - ist auch ein bischen TryAndError erlaubt, um zum Ziel zu gelangen.

Die beiden wichtigsten und gleichzeitig auch die einzigsten cmdlets für das Verwalten von ACLs sind die cmdlets Get-Acl und Set-Acl

Beide cmdlets werden sowohl für die Verwaltung von Berechtigungen von Ordnern wie auch von Dateien verwendet. Powershell macht hier keinen Unterschied zwischen den Objekttypen.

Die zugehörigen .Net-Klassen lauten 

Wie man sieht, unterscheidet .Net gegenüber der Powershell zwischen Directories und Files. Das Handling beider Klassen ist aber identisch, so dass die meisten der folgenden Beispiele durch einfaches Austausch des Klassennamens für Directories und Files benutzt werden können.

 

3.1 Anzeige von Berechtigungen

Die Beispiele dieses Kapitels zeigen die unterschiedlichen Formate, wie man Berechtigungen eines Verzeichnisse mit dem cmdlet Get-ACL oder mit der .Net Klasse DirectorySecurity anzeigen kann.

Dem Verzeichnis HomeUser001, das ich für die Beispiele in diesem Kapitel verwende, habe ich den Default Berechtigungen zusätzliche Berechtigungen für den Account "karl_napf" zugefügt.


Mit der Powershell kann die NTFS Berechtigungsliste (DACL = Discreationary Access Control List) auf mehrere Weisen angezeigt werden. Je nach Format ist die Ausgabe übersichtlicher, oder mit mehr Informationen ausgestattet

 

Beispiel 1a: verschiedene Möglcihkeiten Berechtigungen eines Verzeichnisses anzeigen (cmdlet Get-Acl)

Set-StrictMode -Version "2.0"
Clear-Host

 
$DirectoryPath="c:\temp\homes\homeuser001"
Get-Acl $DirectoryPath | Select -Expand Access
#(Get-Acl $DirectoryPath).Access #gleichwertig
#Ausgabe gekürzt

FileSystemRights  : Write
AccessControlType : Deny
IdentityReference : DOM1\karl_napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : ReadAndExecute, Synchronize
AccessControlType : Allow
IdentityReference : DOM1\karl_napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

 

Set-StrictMode -Version "2.0"
Clear-Host

 
$DirectoryPath="c:\temp\homes\homeuser001"
(Get-Acl $DirectoryPath).AccessToString
#Ausgabe

DOM1\karl_napf Deny  Write
DOM1\karl_napf Allow  ReadAndExecute, Synchronize
VORDEFINIERT\Administratoren Allow  FullControl
VORDEFINIERT\Administratoren Allow  268435456
NT-AUTORITÄT\SYSTEM Allow  FullControl
NT-AUTORITÄT\SYSTEM Allow  268435456
VORDEFINIERT\Benutzer Allow  ReadAndExecute, Synchronize
NT-AUTORITÄT\Authentifizierte Benutzer Allow  Modify, Synchronize
NT-AUTORITÄT\Authentifizierte Benutzer Allow  -536805376

 

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="c:\temp\homes\homeuser001"
Get-Acl $DirectoryPath | Format-List
#Ausgabe

Path   : Microsoft.PowerShell.Core\FileSystem::C:\temp\homes\homeuser001
Owner  : VORDEFINIERT\Administratoren
Group  : DOM1\Domänen-Benutzer
Access : DOM1\karl_napf Deny  Write
         DOM1\karl_napf Allow  ReadAndExecute, Synchronize
         VORDEFINIERT\Administratoren Allow  FullControl
         VORDEFINIERT\Administratoren Allow  268435456
         NT-AUTORITÄT\SYSTEM Allow  FullControl
         NT-AUTORITÄT\SYSTEM Allow  268435456
         VORDEFINIERT\Benutzer Allow  ReadAndExecute, Synchronize
         NT-AUTORITÄT\Authentifizierte Benutzer Allow  Modify, Synchronize
         NT-AUTORITÄT\Authentifizierte Benutzer Allow  -536805376
Audit  :
Sddl   : O:BAG:DUD:AI(D;OICI;DCLCRPCR;;;S-1-5-21-3207648952-1170633684-1844968635-9004)

              (A;OICI;0x1200a9;;;S-1-5-21-3207648952-1170633684-1844968635-9004)(A;ID;FA;;;BA)(A;O
         ICIIOID;GA;;;BA)(A;ID;FA;;;SY)(A;OICIIOID;GA;;;SY)(A;OICIID;0x1200a9;;;BU)

                  (A;ID;0x1301bf;;;AU)(A;OICIIOID;SDGXGWGR;;;AU)

Neben der Eigenschaft "Access" (=AccessControlList ACL) bekommt man hier noch einige andere Eigenschaften des Verzeichnisses angezeigt wie Path, Owner, Group, Audit und Sddl. Die Eigenschaft Owner behandle ich im Kapitel 3.3 Besitzer (Owner)

 

Beispiel 1b: Berechtigungen eines Verzeichnisses anzeigen (.Net Klasse DirectorySecurity)

Set-StrictMode -Version "2.0"
Clear-Host
$DirectoryPath = "c:\temp\homes\homeuser001"
 
$DirectoryInfo = New-Object System.IO.DirectoryInfo($DirectoryPath)
$DirectorySecurity = $DirectoryInfo.GetAccessControl()
$DirectorySecurity | Select -Expand Access
#$DirectorySecurity.Access #gleichwertig
Set-StrictMode -Version "2.0"
Clear-Host

 
$DirectoryPath = "c:\temp\homes\homeuser001"
 $DirectoryPath = "c:\temp\homes\homeuser001"
$DirectoryInfo = New-Object System.IO.DirectoryInfo($DirectoryPath)
$DirectorySecurity = $DirectoryInfo.GetAccessControl()
$DirectorySecurity | Format-List
Set-StrictMode -Version "2.0"
Clear-Host
$DirectoryPath = "c:\temp\homes\homeuser001"
 
$DirectoryPath = "c:\temp\homes\homeuser001"
$DirectoryInfo = New-Object System.IO.DirectoryInfo($DirectoryPath)
$DirectorySecurity = $DirectoryInfo.GetAccessControl()
$DirectorySecurity.AccessToString

liefern jeweils sehr ähnliche Ergebnisse wie in Beispiel 1a mit dem cmdlet Get-Acl zu sehen sind.

MSDN:  DirectorySecurity Klasse
 
Beispiel 2: Formatierte Ausgabe der ACL (Darstellungsformen der FileSystemRights)

$DirectoryPath = "c:\temp\homes\homeuser001"
$DirectoryInfo = New-Object System.IO.DirectoryInfo($DirectoryPath)
$DirectorySecurity = $DirectoryInfo.GetAccessControl()
#$DirectorySecurity=Get-Acl $DirectoryPath  #Alternative

$headline= "{0,-43} {1,-30} {2,-28} {3,-21}" -f `
   "`nIdentityReference","FileSystemRights","FSR(d)","FSR(b)"
   
#$headline= "{0,-43} {1,-30} {2,-28} {3,-21} {4,-9} {5}" -f `
  # "`nIdentityReference","FileSystemRights","FSR(d)","FSR(b)","ACT","II   "
   

Write-Host -BackgroundColor darkyellow -foregroundcolor darkred "$headline`n"

$ACL=$DirectorySecurity.Access
$ACL=$ACL | sort
$ACL | foreach{
   $Identity=$_.IdentityReference
   $FileSystemRights=$_.FileSystemRights
   $dezFileSystemRights=($_.FileSystemRights).value__
   #$binFileSystemRights=$([Convert]::ToString($(($_.FileSystemRights).value__), 2))
   $binFileSystemRights=$([Convert]::ToString($dezFileSystemRights, 2))
   $AccessControlType=$_.AccessControlType
   $IsInherited=$_.IsInherited
   
   "{0,-42} {1,-30} {2,-15} {3,32}" -f `
        $Identity,$FileSystemRights,$dezFileSystemRights, $binFileSystemRights #,$AccessControlType,$IsInherited
    
    #"{0,-42} {1,-30} {2,-15} {3,32}   {4,-9} {5}" -f `
        #$Identity,$FileSystemRights,$dezFileSystemRights, $binFileSystemRights,$AccessControlType,$IsInherited
}


Write-Host -B darkyellow "`n`nFSR(d) - FileSystemRights (dezimal) `nFSR(b) - FileSystemRights (binär)"
#Write-Host -B darkyellow "`n`nFSR(d) - FileSystemRights (dezimal) `nFSR(b) - FileSystemRights (binär)
#   `nACT - AccessControlType `nII - IsInherited (Vererbt)"

#mögliche Ausgabe

IdentityReference                          FileSystemRights               FSR(d)                       FSR(b)

VORDEFINIERT\Benutzer                      ReadAndExecute, Synchronize    1179817                    100100000000010101001
NT-AUTORITÄT\SYSTEM                        268435456                      268435456          10000000000000000000000000000
NT-AUTORITÄT\Authentifizierte Benutzer     -536805376                     -536805376      11100000000000010000000000000000
NT-AUTORITÄT\Authentifizierte Benutzer     Modify, Synchronize            1245631                    100110000000110111111
NT-AUTORITÄT\SYSTEM                        FullControl                    2032127                    111110000000111111111
DOM1\Karl_Napf                             ReadAndExecute, Synchronize    1179817                    100100000000010101001
DOM1\Karl_Napf                             Write                          278                                    100010110
VORDEFINIERT\Administratoren               268435456                      268435456          10000000000000000000000000000
VORDEFINIERT\Administratoren               FullControl                    2032127                    111110000000111111111

FSR(d) - FileSystemRights (dezimal)
FSR(b) - FileSystemRights (binär)


Ich habe das Beispiel hier etwas eingeschränkt und die etwas weniger interessanten Eigenschaften "AccessControlType" sowie "IsInherited" aus Darstellungsgründen weggelassen.
Im Skript habe ich den Code mit diesen beiden Eigenschaften eingebaut, allerdings mit "#" auskommentiert.

Die binäre Form der FileSystemRights in Spalte FSR(b) werden wir im folgenden Kapitel 3.2.1.1 FilesystemRights benötigen.

 

Beispiel 3a: Prüfen, ob das Skript Berechtigungen auf ein Verzeichnis besitzt (If/ Else)

Clear-Host

$Folder = "C:\test\"
If( !(Test-Path $Folder) )
{   
   Get-ChildItem $Folder
}Else{
  Write-Host "Fehler : Zugriff verweigert!"
}

 

Beispiel 3a: Prüfen, ob das Skript Berechtigungen auf ein Verzeichnis besitzt (Try/ Catch)

Clear-Host

$Folder = "C:\test\"
Try
{   
    Test-Path $Foilder
    Get-ChildItem $Folder
}Catch{     write-host "Fehler : Zugriff verweigert!" }

Ohne den Test-Path Befehl, würde ein Fehler geworfen, wenn kein Zugriff auf den Folder möglich ist

 

3.2 Berechtigungen auf Verzeichnisse und Dateien setzen

Im nächsten Kapitel 3.2.1 werde ich ein bischen auf die Theorie eingehen, die für das Verständnis von Berechtigungen sicher hilfreich ist.
In Kapitel 3.2.2 habe ich einige Beispiele, die aufbauend auf der vorangegangenen Theorie zeigen, wie NTFS-Berechtigungen gesetzt werden können.

 

3.2.1 etwas Theorie über ACL und ACE

Alle Berechtigungen zusammen für eine Datei oder ein Verzeichnis nennt man (D)ACL (=Discretionary Access Control List). Diese ACL enthält die einzelnen Berechtigungen dieses Objekts in Form von meist mehreren ACEs (Access Control Entry's). Alle ACEs (=ACL) bestimmen im Ergebnis, wer oder wer nicht mit einem Objekt was tun darf oder eben nicht.
 
Beispiel 1a: ACL eines Verzeichnisses

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="c:\temp\homes\homeuser001"
(Get-Acl $DirectoryPath).AccessToString
#Ausgabe

DOM1\karl_napf Deny  Write
DOM1\karl_napf Allow  ReadAndExecute, Synchronize
VORDEFINIERT\Administratoren Allow  FullControl
VORDEFINIERT\Administratoren Allow  268435456
NT-AUTORITÄT\SYSTEM Allow  FullControl
NT-AUTORITÄT\SYSTEM Allow  268435456
VORDEFINIERT\Benutzer Allow  ReadAndExecute, Synchronize
NT-AUTORITÄT\Authentifizierte Benutzer Allow  Modify, Synchronize
NT-AUTORITÄT\Authentifizierte Benutzer Allow  -536805376

jede Zeile stellt eine ACE dar. Die erste ausgegebene Zeile dieses Beispiels "DOM1\karl_napf Deny  Write" wird im folgenden Beispiel 1b noch genauer dargestellt.

 

Beispiel 1b: Eine einzelne ACE

$DirectoryPath="c:\temp\homes\homeuser001"
Get-Acl $DirectoryPath | Select -Expand Access
# (Get-Acl $DirectoryPath).Access #gleichwertig
#Ausgabe gekürzt

FileSystemRights  : Write
AccessControlType : Deny
IdentityReference : DOM1\karl_napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

Neben den Eigenschaften IdentityReference, AccessControlType und FileSystemRights, die bereits in Beispiel 1a tabellarisch zu sehen sind, kommen hier die drei weiteren Eigenschaften IsInherited, InheritanceFlags und PropagationFlags hinzu.

Um das Berechtigungssystem zu verstehen, muss man die Bedeutung dieser Eigenschaften sowie deren mögliche Werte kennen. In den nachfolgenden Kapiteln gehe ich daher näher auf jede Property ein. Genaugenommen handelt es sich nicht nur um Eigenschaften, sondern auch um Aufzählungen (Enumerationen) aus dem Namespace "System.Security.AccessControl"

MSDN: FileSystemAccessRule-Eigenschaften

 

3.2.1.1 FileSystemRights (Write, Read, Delete,...)

MSDN: Access Mask Format

Gleich die erste Eigenschaft "FileSystemRights" dürfte die komplexeste Eigenschaft einer ACE sein. Über die GUI ist ihr sicher schon jeder mal begegnet. Intern liegt "FileSystemRights" als 32-bit AccessMask vor.

Auf die praktische Bedeutung jedes Bits für die resultierende Gesamtberechtigung gehe ich nicht näher ein.  

Das Filesystemrights "Write" hat binär den Wert "100010110" (278). Den Binärwert könnte man zum besseren Verständnis nach Links mit Nullen aufüllen, bis 32 Stellen belegt sind.


Beispiel 1: Filesystemrights als Text und Bits (Flags)

MSDN: FileSystemRights-Enumeration

Set-StrictMode -Version "2.0"
Clear-Host
 

[Enum]::GetValues([System.Security.AccessControl.FileSystemRights]) | %{
  "{0,-30}  {1,20} ({2}) " -f $([String]$_), [Convert]::ToString($_.value__,2), $_.value__
}
#Ausgabe gekürzt

ReadData                                           1 (1)
CreateFiles                                       10 (2)
AppendData                                       100 (4)
ReadExtendedAttributes                          1000 (8)
WriteExtendedAttributes                        10000 (16)
ExecuteFile                                   100000 (32)
DeleteSubdirectoriesAndFiles                 1000000 (64)
ReadAttributes                              10000000 (128)
WriteAttributes                            100000000 (256)
Write                                      100010110 (278)
Delete                             10000000000000000 (65536)
ReadPermissions                   100000000000000000 (131072)
Read                              100000000010001001 (131209)
ReadAndExecute                    100000000010101001 (131241)
Modify                            110000000110111111 (197055)
ChangePermissions                1000000000000000000 (262144)
TakeOwnership                   10000000000000000000 (524288)
Synchronize                    100000000000000000000 (1048576)
FullControl                    111110000000111111111 (2032127)
  • Bei FullControl und Synchronize ist Bit 21 das höchstwertige (2^20)
  • Bei Modify ist Bit 18 das höchstwertige (2^17)
  • Bei Write ist Bit 9 das höchstwertige (2^8)

Sind die oberen Bits (Generic Bits) zwischen 28 und 31 belegt, so erhält man - wie in Beispiel 1a in Kapitel "3.2.1 etwas Theorie" bei zwei ACEs - nicht die ausformulierten Berechtigungen wie Read und Write, sondern Zahlenwerte, wie

10000000000000000000000000000 (268435456) 
11111111111110000000000000000 (536805376)

Das oberste Bit 28 repäsentiert die Berechtigung GA (Generic_All). Generic_All beinhaltet die Berechtigungen "Read, Write, and Execute Access" der Bits 29 bis 31.
MSDN: Generic Access Rights

Ich vermute, dass Generic Access Rights in einer frühen Phase der Windowsinstallation gesetzt werden, damit einige Konten problemlos auf wichtige Verzeichnisse zugreifen können. Erst später werden die differenzierteren Berechtigungen gesetzt. Das ist meine Interpretation, da ich keine andere Erklärung gefunden habe!
Wenn jemand eine bessere Erklärung der Generic Access Rights findet, oder gar das Minuszeichen vor 536805376 erklären kann, ist herzlich ins Scriptingforum des MCSEboards eingeladen, sein Wissen mitzuteilen.
 

In der GUI sieht die obige Berechtigung "Write-Deny" für karl_napf so aus:

Im linken Fenster findet man im unteren Teil einige Bits der AccessMask zwischen 16 und 23 (Standard Access Rights) wieder, im rechten Fenster viele der Bits zwischen 0 und 15 (Object-specific access rights).
Eine durchgängige 1:1 Beziehung zwischen den Bits und den Checkboxen der GUI besteht aber nicht.

 

3.2.1.2 AccessControlType (Zulassen und Verweigern)

MSDN: AccessControlType-Enumeration

Im Vergleich zu den FileSystemrights im vorigen Kapitel sind die möglichen Werte für die Eigenschaft "AccessControlType" überschaubarer

 

Beispiel 1: Anzeige der Werte aus AccessControlType

Diese Werte sind keine Flags und können daher nicht kombiniert werden

Set-StrictMode -Version "2.0"
Clear-Host

 
[Enum]::GetValues([System.Security.AccessControl.AccessControlType]) | %{
   "{0,-8}  {1} " -f $([String]$_),  $_.value__
}
#Ausgabe

Allow     0
Deny      1

.

3.2.1.3 IdentityReference

MSDN: AuthorizationRule.IdentityReference-Eigenschaft

Beispiel 1: Bestimmen der zurückgegebenen Klasse

Set-StrictMode -Version "2.0"
Clear-Host
 
$DirectoryPath = "c:\temp\homes\homeuser001"
$DirectorySecurity=Get-Acl $DirectoryPath  #Alternative
$ACL=$DirectorySecurity.access
$ACL[0].IdentityReference
($ACL[0].IdentityReference).gettype() | Format-Table Name,BaseType -auto
#Ausgabe

Value                                                                                                                     
-----                                                                                                                     
DOM1\Karl_Napf                                                                                                              
Name      BaseType                                   
----      --------                                   
NTAccount System.Security.Principal.IdentityReference

Man erhält also ein Objekt der Klasse NTAccount

MSDN: NTAccount-Klasse

 

3.2.1.4 IsInherited

Dieser boolesche Wert zeigt an, ob der Wert aus einer höheren Ebene vererbt wurde. In der GUI unter "Eigenschaften" -> "Berechtigungen" (siehe Bild im Kapitel 3.2.1.1)  erkennt man den Unterschied zwischen $True und $False am dunkleren oder helleren Farbton der Haken.

 

3.2.1.5 InheritanceFlags

Der Wert der Eigenschaft "InheritanceFlags" kann drei Werte annehmen, die kombinierbar sind.

 

Beispiel 1: Anzeige der InheritanceFlags

Set-StrictMode -Version "2.0"
Clear-Host
 
[Enum]::GetValues([System.Security.AccessControl.InheritanceFlags]) | %{
  "{0,-18}  {1} " -f $([String]$_),  $_.value__
}
#Ausgabe

None                0
ContainerInherit    1
ObjectInherit       2

MSDN: InheritanceFlags-Enumeration

Dieser Flag gibt an, ob und auf welche Objekttypen (Ordner oder Dateien) die Berechtigung gesetzt werden soll.

In der GUI wird der Wert in Dropdown Menü "Übernehmen für" gesetzt:
Microsoft Support:: Understanding Container Access Inheritance Flags in Windows 2000

 

3.2.1.6 PropagationFlags

 

Beispiel 1: Anzeige der PropagationFlags

Set-StrictMode -Version "2.0"
Clear-Host
 
[Enum]::GetValues([System.Security.AccessControl.PropagationFlags]) | %{
  "{0,-18}  {1} " -f $([String]$_),  $_.value__
}

#Ausgabe

None                0
NoPropagateInherit  1
InheritOnly         2

Die PropagationFlags geben an, auf welcher Ebene die Berechtigungen wirken sollen. (siehe GUI-Bild in Kapitel 3.2.1.5)

  • None (Bit 0) - die Berechtigung wird auf den aktuellen Ordner angewendet
  • InheritOnly (Bit 2) - die Berechtigung wird nur auf die untergeordneten Objekte angewendet.
  •  

3.2.2.1 ACLs verändern

 

Beispiel 1: Überprüfen der Berechtigungen eines Users oder Gruppe

Set-StrictMode -Version "2.0"
Clear-Host
 
$DirectoryPath="c:\temp\homes\homeuser001"
$IdentityRef = "DOM1\Karl_Napf"  #User oder Group
$ACL = Get-ACL $DirectoryPath
$ACL.Access | where {$_.IdentityReference -eq $IdentityRef}
 
#$ACL.Access |Where IdentityReference -eq $IdentityRef #PS V3.0
#mögliche Ausgabe

FileSystemRights  : CreateFiles
AccessControlType : Deny
IdentityReference : DOM1\karl_napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : ReadData, WriteExtendedAttributes
AccessControlType : Deny
IdentityReference : DOM1\karl_napf
IsInherited       : False
InheritanceFlags  : ObjectInherit
PropagationFlags  : InheritOnly

Dieses Skript zeigt die ACEs von Karl_Napf an. Dieses Skript dient für mich mehr als Kontrollwerkzeug zum Entwickeln der nachfolgenden Skripte. Dadurch braucht man nicht jedesmal in die GUI, um zu sehen, ob das Setzen oder Entfernen von ACEs funktioniert hat.

(Get-Acl $DirectoryPath).Access liefert für diesen Zweck oft zuviel Output

 

Beispiel 2: Übertragen der gesamten ACL mit Get-ACL und Set-ACL

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath_org="c:\temp\homes\homeuser001"
$DirectoryPath_dest="c:\temp\homes\homeuser002"

$ACL=Get-Acl $DirectoryPath_org
Set-Acl -path $DirectoryPath_dest -AclObject $ACL

# Kopieren der Berechtigungen über eine Pipe
# Get-Acl $DirectoryPath_org | $DirectoryPath_dest

Die Berechtigungen beider Directories sind nun identisch. Vorhandene Berechtigungen auf dem Zielverzeichnis wurden überschrieben.

(Get-Acl $DirectoryPath).Access wird für beide Directories dieselbe ACL mit ihren ACEs anzeigen

FileSystemRights 
AccessControlType
IdentityReference
IsInherited     
InheritanceFlags 
PropagationFlags 

siehe dazu auch: Kapitel 3.1 Anzeige von Berechtigungen -> Beispiel 1a: Berechtigungen eines Verzeichnisses anzeigen (Get-Acl)

Mit diesem "Trick" ist es einfach, gewünschte Berechtigungen zu setzen. Man erstellt sich zuerst auf einem Dummyverzeichnis oder einer Dummydatei per GUI die gewünschten Berechtigungen und überträgt diese - wie in dem Beispiel eben gezeigt - auf das Zielverzeichnis.

 

Beispiel 3: Löschen aller ACEs eines Users oder Gruppe aus einem Verzeichnis

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="c:\temp\homes\homeuser001"
$IdentityRef = "DOM1\Karl_Napf"  #User oder Group

$ACL = Get-ACL $DirectoryPath
$ACEs=(Get-Acl $DirectoryPath).Access | where {$_.IdentityReference -eq $IdentityRef}
$ACEs | foreach{
    try{
    $null=$ACL.RemoveAccessRule($_)
    Set-ACL $DirectoryPath $ACL
    "ACE für $IdentityRef erfolgreich entfernt"
    }
    catch{
    #keine ACE mehr vorhanden
    }
 }

#mögliche Ausgabe

ACE für DOM1\Karl_Napf erfolgreich entfernt
ACE für DOM1\Karl_Napf erfolgreich entfernt

Da in einer ACL ein User oder eine Gruppe (=IdentityReference) wie im folgenden Bild dargestellt mehrfach mit verschiedenen Berechtigungen vorkommen kann, geschieht das Entfernen einer Reference über eine foreach-Schleife.
Vererbte Berechtigungen können damit natürlich nicht entfernt werden.

 

3.2.2.2 ACE erzeugen und als Berechtigung hinzufügen

 

Beispiel 1a: Erzeugen einer ACE und Setzen (Klasse FileSystemRights)

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="c:\temp\homes\homeuser001"
$IdentityRef = "DOM1\Karl_Napf"  #User oder Group

#$FileSystemRights = [System.Security.AccessControl.FileSystemRights]"131487"
$FileSystemRights = [System.Security.AccessControl.FileSystemRights]"Write,Read"

$InheritanceFlag1 = [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
$InheritanceFlag2 = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit
$InheritanceFlag=$InheritanceFlag1 -bor $InheritanceFlag2

$PropagationFlag = [System.Security.AccessControl.PropagationFlags]::InheritOnly
$AccessControlType =[System.Security.AccessControl.AccessControlType]::Allow
$User = New-Object System.Security.Principal.NTAccount($IdentityRef)

$ACE = New-Object System.Security.AccessControl.FileSystemAccessRule($User, $FileSystemRights,`
    $InheritanceFlag, $PropagationFlag, $AccessControlType)
$ACL = Get-ACL $DirectoryPath
$ACL.AddAccessRule($ACE)

Set-ACL $DirectoryPath $ACL
  • Für FileSystemRights können die Werte aus der Tabelle in Kapitel 3.2.1.1 FileSystemRights genutzt werden. Dafür lassen sich sowohl die Bitwerte, wie auch die Berechtigungen als Worte, kombinieren. Ich konnte nur die ersten 21 Bits setzen. Zumindest konnte ich die Bits über 23 (GR, GW, GA, GE, AS) nicht benutzen, was so schlimm denke ich aber nicht ist.
  • In diesem Beispiel habe ich die InheritanceFlags "ContainerInherit" und "ObjectInherit" binär kombiniert, so dass die ACE sowohl auf untergeordnete Verzeichnisse wie auf Dateien wirkt
  • Die neue ACL kann man sich entweder in der GUI ansehen, oder das folgende Beispiel 1b benuntzen.
  •  

Beispiel 1b: Abfrage der neuen ACL mit der neuen ACE

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="c:\temp\homes\homeuser001"
$IdentityRef = "DOM1\Karl_napf"  #User oder Group
$ACL = Get-ACL $DirectoryPath
$ACL.Access | where {$_.IdentityReference -eq $IdentityRef}
#Ausgabe

FileSystemRights  : Write, Read, Synchronize
AccessControlType : Allow
IdentityReference : DOM1\Karl_Napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

 
Beispiel 2: Erzeugen einer ACE und Setzen (Klasse FileSystemAccessRule)

.Net bietet mit der Klasse "FileSystemAccessRule" noch eine etwas einfachere Möglichkeit als die Klasse FileSystemRights an, ACEs auf eine NTFS-Objekt zu setzen

MSDN: FileSystemAccessRule Class

Set-StrictMode -Version "2.0"
Clear-Host

$ACL = Get-Acl $DirectoryPath
$ACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
  ("DOM1\Karl_Napf","Write, Read", "ContainerInherit, ObjectInherit", "Inheritonly", "Allow")
$ACL.AddAccessRule($ACE)
Set-Acl $DirectoryPath $ACL

$ACL.Access | where {$_.IdentityReference -eq "DOM1\Karl_Napf"}
#identische Ausgabe wie in Beispiel 1b

FileSystemRights  : Write, Read, Synchronize
AccessControlType : Allow
IdentityReference : DOM1\Karl_Napf
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

Ich habe diesen Konstruktor genutzt:
MSDN: FileSystemAccessRule Constructor (IdentityReference, FileSystemRights, InheritanceFlags, PropagationFlags, AccessControlType)

Damit spart man sich den Aufwand, die einzelnen ACE-Bestandteile extra als Objekte definieren zu müssen.,

 

3.2.2.3 Vererbung unterbrechen

Als letzte Optionen in diesem Kapitel zeige ich hier, wie die Vererbung unterbrochen werden kann. Dazu kann man entweder alle aus einem übergeordneten Verzeichnis geererbten ACEs blockieren oder diese in nicht vererbte ACEs umwandeln.

Beide Varianten kann man über die MethodeSetAccessRuleProtection erreichen

Beispiel 1: Vererbte Berechtigungen durch vererbbare Berechtigungen ersetzen

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="C:\temp\Homes\HomeUser001"

$ACL = Get-Acl $DirectoryPath
 
#Unterbrechung der Vererbung, Beibehaltung der Berechtigungen
$ACL.SetAccessRuleProtection($True, $True)

#neue ACL erzeugen, dazu wird ein Dummy (Karl_Napf) benötigt
$ACE = New-Object System.Security.AccessControl.FileSystemAccessRule `
 ("DOM1\Karl_Napf","Write, Read", "ContainerInherit, ObjectInherit", "Inheritonly", "Allow")
$ACL.AddAccessRule($ACE)
Set-Acl $DirectoryPath $ACL

#eventuell Entfernen des Dummys
#$null=$ACL.RemoveAccessRule($ACE)
#Set-ACL $DirectoryPath $ACL

Ergebnis: Berechtigungen, die vorher von übergeordneten Verzeichnissen geerbt wurden, stehen nun auf <nicht geerbt>

 

Beispiel 2: Löschen vererbter Berechtigungen

Set-StrictMode -Version "2.0"
Clear-Host

$DirectoryPath="C:\temp\Homes\HomeUser001"

$ACL = Get-Acl $DirectoryPath
$ACL.SetAccessRuleProtection($True, $False)

$ACE = New-Object System.Security.AccessControl.FileSystemAccessRule("DOM1\Karl_Napf", `

   "Write, Read","ContainerInherit, ObjectInherit", "Inheritonly", "Allow")
$ACL.AddAccessRule($ACE)
Set-Acl $DirectoryPath $ACL

$ACL.SetAccessRuleProtection($True, $False) löscht alle vererbten Berechtigungen.

 

3.3 Besitzer (Owner)

Technet - Scripting Guy: How Can I Use Windows PowerShell to Determine the Owner of a File?

Jeder Ordner und jede Datei besitzen einen Owner (Ich bleibe ab jetzt bei dem englischen Begriff). Das Besondere am Owner ist, dass er sich selbst fehlende NTFS-Rechte setzen kann. Fehlen beispielsweise einem Admin Rechte um Objekte zu öffnen oder zu bearbeiten, so kann er sich als Admin die Ownership verschaffen und damit die weiteren Securitysettings (DACL) nach seinem Bedarf setzen.

Das Auslesen oder Setzen der Ownership ist ansich mit den cmdlets get-acl und set-acl sowie den zugehörigen .Net-Klassen relativ einfach


Beispiel 1: Anzeige des Owners einer Datei

$Path = "C:\temp\homes\homeuser001\file001.xlsx"
(Get-Acl $Path).Owner

#getestet unter PSH V2.0
#mögliche Ausgabe

myPC\KarlNapf

Oft zeige ich in meinen Beispielen den alternativen Weg über die .Net Klasse

Sehen wir uns also mit Get-Member einmal an, von welchem Typ das von Get-Acl zurückgelieferte Objekt ist und welche Methoden zum Auslesen und Setzen der Ownership zur Verfügung stehen. 

$Path = "C:\temp\homes\homeuser001\file001.xlsx"
(Get-Acl $Path).GetType() | Format-Table Name,BaseType -auto
(Get-Acl $Path).PsExtended | Get-Member

#getestet unter PSH V2.0
#Ausgabe gekürzt

Name         BaseType      
----         --------      
FileSecurity System.Security.AccessControl.FileSystemSecurity

Name               MemberType
----               ----------
Access           CodeProperty
Group            CodeProperty
Owner            CodeProperty
Path             CodeProperty
Sddl             CodeProperty
PSChildName      NoteProperty
PSDrive          NoteProperty
PSParentPath     NoteProperty
PSPath           NoteProperty
PSProvider       NoteProperty
AccessToString   ScriptProperty
AuditToString    ScriptProperty

Anmerkung: ein (get-acl $path) | get-member hätte die Information genauso ausgegeben, allerdings zusammen mit allen nativen Methoden und Eigenschaften der Klasse "FileSystemSecurity".

Man kann an der Ausgabe sehen, daß die Eigenschaft "Owner" eine sogenannte Codeproperty ist. Diese Eigenschaft kommt also nicht von der .Net Klasse, sondern wurde dem cmdlet get-acl von den Powershellentwicklern zusätzlich "spendiert". Auch die .Net Klasse FileSystemSecurity besitzt eine Methode getowner() mit, doch ist diese bei weitem nicht so einfach zu benutzen wie die Codeproperty "owner". Zumindest beim Ermitteln des Owners sind wir durch diese Erweiterung mit der Powershell im Vorteil gegenüber anderen Programmiersprachen.


Beispiel 2a: Setzen des angemeldeten Benutzers als neuen Owner
(vergleiche den Scripting Guy Artikel)

$Path = "C:\temp\homes\homeuser001\file001.ps1"
$Domain="dom1"
$NewOwner="Karl_Napf"

$objUser = New-Object System.Security.Principal.NTAccount($Domain, $NewOwner)
$objFile = Get-Acl $Path
$objFile.SetOwner($objUser)
Set-Acl -aclobject $objFile -path $Path
"Neuer Eigentümer: {0}" -f $(Get-Acl $Path).Owner

#getestet unter PSH V2.0
#mögliche Ausgabe

Neuer Eigentümer: DOM1\Karl_Napf

Dieses Beispiel funktioniert einwandfrei, solange der neue Owner gleich dem angemeldeten Benutzer sein soll. Ist dies nicht der Fall erhält man diese Fehlermeldung:

Set-Acl : Die Sicherheits-ID darf nicht der Besitzer dieses Objekts sein.

Das Problem sind fehlende Privileges.


Beispiel 2b: Setzen eines beliebigen Benutzers oder einer beliebigen Gruppe als neuen Owner
In der MSDN findet man ein Powershellskript, welches mit den WMI-Klassen Win32_SecurityDescriptor, Win32_Trustee und Win32_LogicalFileSecuritySetting die Privileges so abändert, dass tatsächlich ein beliebiger User oder auch eine Gruppe als Owner einer Datei oder eines Verzeichnisses gesetzt werden können.

MSDN: SetSecurityDescriptor method of the Win32_LogicalFileSecuritySetting Class -> Community Content -> Script example in PowerShell 1.

Function Set-Owner ($user, $Path) { 
if (!(Test-Path $Path)) {Write-Warning "Specified path is incorrect"} 
else { 
    # replace path from C:\Folder to C:\\Folder 
    $path = $path.replace("\", "\\") 
    # create SecurityDescriptor appropriated classes 
    $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
    $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() 
    # translate user/group name to SID and write information to
    # Trustee properties 
    $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) 
    [byte[]] $SIDArray = ,0 * $SID.BinaryLength 
    $SID.GetBinaryForm($SIDArray,0) 
    $Trustee.Name = $user 
    $Trustee.SID = $SIDArray 
    $SD.Owner = $Trustee 
    # set control flag 
    $SD.ControlFlags="0x8000" 
    # get file or folder object 
    $wPrivilege = gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'" 
    # enable SeRestorePrivilege (for Windows Vista and Windows Server 2008
    # not neccessary if running in privileged mode)
    $wPrivilege.psbase.Scope.Options.EnablePrivileges = $true 
    # Write  new SecurityDescriptor to file/folder object
    $wPrivilege.setsecuritydescriptor($SD)
   } #if

  #script usage: Set-Owner everyone D:\Users
} #function


$path="C:\temp\Homes\HomeUser001"
$newOwner="Karl_Napf@Dom1.Intern"
$NewOwner="Dom1\Karl_Napf"

$Null=Set-Owner $NewOwner $path
"Neuer Owner von {0} ist {1}" -f $path,$((get-acl $path).owner)

 

In diesem Skript stecken einige technische Kniffe! . Es funktioniert jedenfalls, das habe ich getestet.