A fájlrendszer és a registry objektumainál kiolvasható a hozzáférési lista a get-acl cmdlet segítségével:
[87] PS C:\> get-acl C:\powershell2\scripts\1.txt | fl
Path : Microsoft.PowerShell.Core\FileSystem::C:\powershell2\scripts\1.txt
Owner : ASUS\Administrator
Group : ASUS\None
Access : BUILTIN\Administrators Allow FullControl
NT AUTHORITY\SYSTEM Allow FullControl
ASUS\Administrator Allow FullControl
BUILTIN\Users Allow ReadAndExecute, Synchronize
Audit :
Sddl : O:LAG:S-1-5-21-2919093906-1695458891-47906081-513D:(A;ID;FA;;;BA)(
A;ID;FA;;;SY)(A;ID;FA;;;LA)(A;ID;0x1200a9;;;BU)
Az így visszakapott objektum egy FileSecurity típusú objektum, melynek a fent látható tulajdonságai közül az Sddl elég rémisztőnek néz ki, de szerencsére nem muszáj azzal foglalkozni, emberi fogyasztásra jobban alkalmas hozzáférési szabályok segítségével is lehet beállítani a hozzáférést a fájlokhoz, könyvtárakhoz. A hozzáférési lehetőségeket a következő táblázat tartalmazza:
Hozzáférési jogok
(FileSystemRights) |
|
ListDirectory ReadData WriteData CreateFiles CreateDirectories AppendData ReadExtendedAttributes WriteExtendedAttributes Traverse ExecuteFile DeleteSubdirectoriesAndFilesReadAttributes |
WriteAttributes Write Delete ReadPermissions Read ReadAndExecute Modify ChangePermissions TakeOwnership Synchronize FullControl |
Ezek közül lehet összerakni a kívánt hozzáférési lehetőségeket a következő módon:
[17] PS C:\> $Acl = Get-Acl C:\scripts
[18] PS C:\> $entry = New-Object System.Security.AccessControl.FileSystemAcc
essRule("Szkriptelők","Read","Allow")
[19] PS C:\> $entry
FileSystemRights : Read, Synchronize
AccessControlType : Allow
IdentityReference : Szkriptelők
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
[20] PS C:\> $acl.AddAccessRule($entry)
[21] PS C:\> set-acl C:\scripts $acl
[22] PS C:\> (Get-Acl C:\scripts).Access
FileSystemRights : Read, Synchronize
AccessControlType : Allow
IdentityReference : ASUS\Szkriptelők
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
...
A fenti példában a c:\scripts könyvtárhoz szeretném adni a Szkriptelők csoportot olvasási jogosultsággal. Ehhez a [17]-es sorban kiolvasom a meglevő hozzáférési listát, a [18]-as sorban definiálom az új hozzáférési bejegyzést. Ezt ellenőrzésképpen kiíratom a [19]-es sorban. A [20]-as sorban hozzáadom ezt a bejegyzést a hozzáférési listához. Mivel ezt egyelőre csak a memóriában tárolt $acl objektum tartalmazza, ezért ezt ki is kell írni a könyvtárobjektumra, amit a [21]-es sorban teszek meg a set-acl cmdlettel. Végezetül, a [22]-es sorban ellenőrzésképpen kiolvasom az új hozzáférési listát, amelyben ott szerepel az imént hozzáadott bejegyzés.
Ha ennél pontosabb jogosultság megadásra van szükségem, például Home könyvtárakra akarom a gazdájának a teljes hozzáférést biztosítani úgy, hogy ez leöröklődjön majd az illető alkönyvtáraira, fájljaira, akkor a következő szkriptet használhatom:
$domainname = "domain"
dir \\server\home\* | %{
$acl = get-acl -Path $_.fullname
$user = "$domainname\$($_.name)"
$entry = New-Object System.Security.AccessControl.FileSystemAccessRule(
$user,
"FullControl",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
$acl.AddAccessRule($entry)
Set-Acl -Path $_.fullname -AclObject
$acl
}
Itt is a módszer hasonló az első példában látottakéhoz: először kiolvasom a teljes biztonsági leírót a Get‑ACL segítségével, majd ezt kibővítem egy frissen létrehozott új bejegyzéssel, és fontos nem elfelejtkezni arról, hogy azt ki kell írni a fájlrendszerbe a Set-ACL segítségével.
Megjegyzés:
A registry elemeinek hozzáférési jogosultságait hasonló módon, de a RegistryAccessRule
osztály objektumainak segítségével állíthatjuk be.
Az előzőekben láttuk, hogy a get-acl kimentében a fájl vagy könyvtár tulajdonosa is kiolvasható. Nézzünk ennek felhasználására egy kis szkriptet, mely segítségével a tulajdonosok szerint szortírozom szét a fájlokat:
Set-Location C:\fájlok
Get-ChildItem |
Where-Object {-not $_.PSIsContainer} |
ForEach-Object {
$d = (Get-Acl $_).Owner.Split("\")[1]
if(-not (Test-Path ((get-location).path
+
'\' + $d)))
{
new-item -path (get-location).path
-name $d `
-type directory
| Out-Null
}
Move-Item -path $_.pspath `
-destination ((get-location).path
+
'\' + $d +'\')
}
Az elején beállítom az aktuális könyvtárat, majd kilistáztatom az összes fájlját és alkönyvtárát. Mivel nekem csak a fájlok kellenek, ezért a where-object-tel kiszűröm a PSIsContainer típusú objektumokat.
Az így megmaradt objektumokon egy foreach-object ciklussal végig szaladok. Képzem egy $d változóba a fájl tulajdonosának a nevét. Itt egy kis trükközésre van szükség, hiszen a felhasználó neve tartomány\felhasználónév vagy gépnév\felhasználónév formátumú. Nekem csak a felhasználónév kell, így split()-tel ketté töröm, és veszem a 2. elemet ([1]-es indexű), ami a felhasználói név.
Ezután megvizsgálom a Test-Path cmdlettel, hogy van-e már a névnek megfelelő alkönyvtár. Ha nincs, akkor a new-item cmdlettel létrehozom. Mire a move-item cmdlethez érünk, addigra már biztos van a felhasználónévnek megfelelő alkönyvtár, így át tudom mozgatni oda a fájlt.
Az előzőekben láttuk, hogy a Get-ACl-el ki lehet olvasni a fájlok és mappák tulajdonosait is. De vajon tudjuk-e módosítani ezt a Set-ACL-el?
Létrehoztam egy fájlt SoosTibor felhasználó nevében:
PS C:\> get-acl C:\PSKönyv\MásikEmberFájlja.txt
Directory: C:\PSKönyv
Path Owner Access
---- ----- ------
MásikEmberFájlja.txt SoosTiborPC\SoosTibor BUILTIN\Administrators...
Mi történik, ha a tulajdonost megpróbálom átírni MásikEmber-re?
PS C:\> $account = new-object System.Security.Principal.NTAccount -ArgumentList
SoosTiborPC, MásikEmber
PS C:\> $acl = Get-Acl -Path C:\PSKönyv\MásikEmberFájlja.txt
PS C:\> $acl.SetOwner($account)
PS C:\> $acl | Set-Acl
Set-Acl : The security identifier is not allowed to be the owner of this objec
t.
At line:1 char:8
+ $acl | Set-Acl
+ ~~~~~~~
+ CategoryInfo : InvalidOperation: (C:\PSKönyv\MásikEmberFájlja.
txt:String) [Set-Acl], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Powe
rShell.Commands.SetAclCommand
Annak ellenére kaptam hibát, hogy rendszergazda nevében és emelt szintű jogosultságokkal futtattam a PowerShell-t! Ennek oka nem a PowerShell-ben keresendő, hanem a Windows-ban. Annak ellenére, hogy rendelkezem a szükséges jogosultságokkal, az access tokenemben nincs „élesítve” a szükséges SeRestorePrivilege privilégium. Ezt ellenőrizhetjük a WhoAmI futtatásával:
PS C:\> whoami /priv | Select-String -Pattern "SeRestore"
SeRestorePrivilege Restore files and directories Disa
bled
Lehetne ezt engedélyezni, erre több példát is lehet találni az interneten (pl.: http://www.leeholmes.com/blog/2010/09/24/adjusting-token-privileges-in-powershell/ ), de ehelyett inkább nézzünk egy egyszerűbb megoldást a http://fixingitpro.com blogról! Érdekes módon, ha ugyanezt a fájlt hálózati megosztáson keresztül érjük el (c: helyett \\SoosTiborPC\c$), a fent említett privilégiumra nincs szükségünk:
PS C:\> $acl = Get-Acl -Path \\SoosTiborPC\c$\PSKönyv\MásikEmberFájlja.txt
PS C:\> $acl.SetOwner($account)
PS C:\> $acl | Set-Acl
PS C:\> Get-Acl C:\PSKönyv\MásikEmberFájlja.txt
Directory: C:\PSKönyv
Path Owner Access
---- ----- ------
MásikEmberFájlja.txt SoosTiborPC\MásikEmber BUILTIN\Administrators...
A fájlkiszolgálók üzemeltetése során különösen fontos annak felderítése, hogy hol vannak felszakított öröklődések, illetve hol vannak explicit jogok kiosztva. Ezekkel foglalkozom részletesebben ebben a fejezetben.
Kicsit korábban, a Get-ACL kimenetéből a „sima” format-list nem mutatott meg mindent. Nézzük meg csillagosan:
[17] PS C:\> get-acl C:\sokfájl\alkönyvtár | Format-List *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\sokfájl\alk
önyvtár
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\sokfájl
PSChildName : alkönyvtár
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
AccessToString : R2\G-Oktatók Deny ReadData, AppendData, ReadExtende
dAttributes, WriteExtendedAttributes, Delete, Change
Permissions
R2\G-Oktatók Allow CreateFiles, ExecuteFile, Delete
SubdirectoriesAndFiles, ReadAttributes, WriteAttribu
tes, ReadPermissions, TakeOwnership, Synchronize
NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
BUILTIN\Users Allow ReadAndExecute, Synchronize
BUILTIN\Users Allow AppendData
BUILTIN\Users Allow CreateFiles
CREATOR OWNER Allow 268435456
AuditToString :
Path : Microsoft.PowerShell.Core\FileSystem::C:\sokfájl\alk
önyvtár
Owner : BUILTIN\Administrators
Group : R2\Domain Users
Access : {System.Security.AccessControl.FileSystemAccessRule,
System.Security.AccessControl.FileSystemAccessRule,
System.Security.AccessControl.FileSystemAccessRule,
System.Security.AccessControl.FileSystemAccessRule.
..}
Sddl : O:BAG:DUD:AI(D;OICIID;CCLCSWRPSDWD;;;S-1-5-21-339893
8913-3940250523-927435294-1645)(A;OICIID;0x1a01e2;;;
S-1-5-21-3398938913-3940250523-927435294-1645)(A;OIC
IID;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;0x1200a9;;;B
U)(A;CIID;LC;;;BU)(A;CIID;DC;;;BU)(A;OICIIOID;GA;;;C
O)
AccessRightType : System.Security.AccessControl.FileSystemRights
AccessRuleType : System.Security.AccessControl.FileSystemAccessRule
AuditRuleType : System.Security.AccessControl.FileSystemAuditRule
AreAccessRulesProtected : False
AreAuditRulesProtected : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical : True
Jóval több tulajdonság vált láthatóvá! Ezek közül az AreAccessRulesProtected az öröklődés szempontjából nagyon fontos, hiszen azok a fájlok vagy könyvtárak, ahol ez a tulajdonság $true, ott fel van szakítva az öröklődési lánc, így külön foglalkozni kell velük, ha valamit változtatni akarunk a hozzáférési szabályokon.
Elsőként próbáljuk tehát felderíteni, hogy hol vannak felszakított öröklődésű objektumaink:
[21] PS C:\> Get-ChildItem C:\sokfájl -recurse | Get-Acl | where-object {$_.are
accessrulesprotected}
Directory: C:\sokfájl
Path Owner Access
---- ----- ------
alkönyvtár BUILTIN\Administrators R2\G-Oktatók Deny Rea...
négy.txt BUILTIN\Administrators R2\G-Oktatók Deny Rea...
Hogyan lehetne megszűntetni az öröklődés helyreállítását? Vajon ezt a tulajdonságot közvetlenül átírhatjuk-e?
[23] PS C:\> Get-ChildItem C:\sokfájl -recurse | Get-Acl | where-object {$_.are
accessrulesprotected} | get-member -MemberType property | Format-Table -Wrap
TypeName: System.Security.AccessControl.DirectorySecurity
Name MemberType Definition
---- ---------- ----------
AccessRightType Property System.Type AccessRightType {get;}
AccessRuleType Property System.Type AccessRuleType {get;}
AreAccessRulesCanonical Property System.Boolean AreAccessRulesCanonical {get
;}
AreAccessRulesProtected
Property System.Boolean
AreAccessRulesProtected {get
;}
AreAuditRulesCanonical Property System.Boolean AreAuditRulesCanonical {get;
}
AreAuditRulesProtected Property System.Boolean AreAuditRulesProtected {get;
}
AuditRuleType Property System.Type AuditRuleType {get;}
…
Sajnos csak a get jelleggel, azaz csak leolvasással lehet ehhez a tulajdonsághoz hozzáférni. Szerencsére van ennek átállítására metódus (csak az Access szót tartalmazó metódusok listája):
[25] PS C:\> Get-ChildItem C:\sokfájl -recurse | Get-Acl | where-object {$_.are
accessrulesprotected} | get-member *access* -MemberType method | Format-Table -
Wrap
TypeName: System.Security.AccessControl.DirectorySecurity
Name MemberType Definition
---- ---------- ----------
AccessRuleFactory Method System.Security.AccessControl.AccessRule A
ccessRuleFactory(System.Security.Principal
.IdentityReference identityReference, int
accessMask, bool isInherited, System.Secur
ity.AccessControl.InheritanceFlags inherit
anceFlags, System.Security.AccessControl.P
ropagationFlags propagationFlags, System.S
ecurity.AccessControl.AccessControlType ty
pe)
AddAccessRule Method System.Void AddAccessRule(System.Security.
AccessControl.FileSystemAccessRule rule)
GetAccessRules Method System.Security.AccessControl.Authorizatio
nRuleCollection GetAccessRules(bool includ
eExplicit, bool includeInherited, type tar
getType)
ModifyAccessRule Method bool ModifyAccessRule(System.Security.Acce
ssControl.AccessControlModification modifi
cation, System.Security.AccessControl.Acce
ssRule rule, System.Boolean&, mscorlib, Ve
rsion=2.0.0.0, Culture=neutral, PublicKeyT
oken=b77a5c561934e089 modified)
PurgeAccessRules Method System.Void PurgeAccessRules(System.Securi
ty.Principal.IdentityReference identity)
RemoveAccessRule Method bool RemoveAccessRule(System.Security.Acce
ssControl.FileSystemAccessRule rule)
RemoveAccessRuleAll Method System.Void RemoveAccessRuleAll(System.Sec
urity.AccessControl.FileSystemAccessRule r
ule)
RemoveAccessRuleSpecific Method System.Void RemoveAccessRuleSpecific(Syste
m.Security.AccessControl.FileSystemAccessR
ule rule)
ResetAccessRule Method System.Void ResetAccessRule(System.Securit
y.AccessControl.FileSystemAccessRule rule)
SetAccessRule Method System.Void SetAccessRule(System.Security.
AccessControl.FileSystemAccessRule rule)
SetAccessRuleProtection Method System.Void SetAccessRuleProtection(bool i
sProtected, bool preserveInheritance)
…
Ezek között van az utolsó, a SetAccessRuleProtection. Nézzük, hogyan tudjuk ezt munkára fogni:
[54] PS C:\> Get-ChildItem C:\sokfájl -recurse | Get-Acl | where-object {$_.are
accessrulesprotected} | ForEach-Object {$_.setaccessruleprotection($false,$tru
e); $_ | set-acl}
A SetAccessRuleProtection két paramétert vár, az első, hogy legyen-e „védett” az ACL, azaz legyen-e felszakítva az öröklődés. Most nekünk pont az kell, hogy legyen öröklődés, tehát én erre $false értéket adok. A második paraméternek akkor van szerepe, amikor pont felszakítjuk az öröklődést és azt mondja meg, hogy szeretnénk-e a korábbi öröklött jogokat explicit jogokként rámásolni az ACL listára. Most ennek nincs szerepe, de sajnos kötelező szerepeltetni. A másik nehézség ezzel a metódussal, hogy közvetlenül a $_ változóban tárolt objektumra végrehajtva még nem íródik ki ez az objektum a fájlra, így még kell egy set-acl, amivel ténylegesen kiírjuk a fájlrendszerbe ezt.
Még egy dologra ügyeljünk! Ilyenkor az történt, hogy az öröklött jogok a könyvtárakon és fájlokon megjelentek, de a korábbi explicit jogok is ottmaradtak. Ha ezek nekünk nem kellenek, akkor ezeket le kell szedni. Nézzük ennek módszerét! Elsőként derítsük fel az explicit jogokat:
[70] PS C:\> Get-ChildItem C:\sokfájl\ -Recurse | Get-Acl | ForEach-Object {$_.
access | where-object {! $_.isinherited} }
FileSystemRights : ReadData, AppendData, ReadExtendedAttributes, WriteExtende
dAttributes, Delete, ChangePermissions
AccessControlType : Deny
IdentityReference : R2\G-Oktatók
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
…
Az a baj, hogy az ACE (Access Control Entry, azaz egy bejegyzés az ACL listában) szinten van ábrázolva az öröklődés, viszont egy szinttel feljebb, az ACL szinten lehet eltávolítani a bejegyzéseket. A másik probléma, amivel már a korábbi feladatnál is találkoztunk, hogy vissza is kell írni a módosított ACL-eket a fájlokra, nem elég memóriában elvégezni a műveleteket. A teljes megoldás egy sorban is futtatható módon a következő:
Get-ChildItem C:\sokfájl\ -Recurse | Get-Acl |
ForEach-Object
{$aclnew = $_; $_.access |
where-object
{! $_.isinherited} |
foreach-object
{[void] $aclnew.removeaccessrule($_)};
Set-Acl
-path $aclnew.path -AclObject $aclnew
}
A könnyebb érthetőség kedvéért a szkriptszerkesztő felületén kicsit áttördeltem. Mi történik itt? Veszem a fájlokat, könyvtárakat, veszem az ACL objektumukat, majd képzek egy átmeneti új ACL objektumot, hiszen ezután már az ACL-nek az Access tulajdonságában tárolt ACE objektumai kellenek, így ezen a ponton már a $_ nem az ACL-t tartalmazza, amelyre nekem később szükségem lesz. Szóval elmentettem az ACL objektumot egy változóba, majd ennek ACE bejegyzéseit sorra veszem, és amelyek nem öröklöttek, azokat szépen kiveszem az elmentett ACL objektum ACE listájáról. Ha már nincs több ilyen, akkor az így „megegyelt” ACE listát tartalmazó új ACL objektumot visszaírom a Set-ACL cmdlettel a fájlra vagy könyvtárra. Természetesen lehetne ezt a kis „szkriptet” optimalizálni, például azzal, hogy ha nem is volt változás az ACL objektumon, akkor ne írjuk fel ismét a fájlra, de ezt az olvasóra bízom.
Összefoglalásul elmondható, hogy nem egyszerű az ACL objektumokkal dolgozni, de még mindig sokkal egyszerűbb keresni és tömeges módosításokat végezni PowerShell segítségével, mint a grafikus felületen dolgozni, ahol ugyanezeket a műveleteket szinte reménytelen elvégezni.
Bár a Get-ACL kimenetében úgy tűnik, hogy benne van a SACL lista (mert láthatunk egy AuditToString tulajdonságot), de mégsem, csak ha az –audit kapcsolót is használjuk. Ráadásul ezt csak rendszergazda jogkörrel futtatott PowerShell ablakban használhatjuk:
PS C:\> (Get-Acl C:\Test -Audit).audit
FileSystemRights : DeleteSubdirectoriesAndFiles, Modify, ChangePermissions, T
akeOwnership
AuditFlags : Failure
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None
PS C:\> (Get-Acl C:\Test -Audit).audittostring
NT AUTHORITY\Authenticated Users Failure DeleteSubdirectoriesAndFiles, Modify
, ChangePermissions, TakeOwnership
Az AuditFlags lehet Success és Faliure, a többi beállítást tekintve ugyanúgy működik, mint a DACL lista.