PowerShell: Nadawanie uprawnień do plików i katalogów

13-maj-2018

Zdarza się, że na dysku znajdziesz dzwiwaczny folder, który powstał w trakcie intalacji lub aktualizacji i chcesz go usunąć, ale pojawia się komunikat o braku uprawnień. Jak to? Ja – administrator i brak uprawnień?

Z jakiegoś powodu te „dziwne” foldery są pozabezpieczane! Dobrze się zastanów nim je rzeczywiście usuniesz lub w nich coś pozmieniasz…

No cóż, przyczyna to zwykle zupełnie inny właściciel folderu, brak włączonego dziedziczenia uprawnień i wreszcie brak nadanych uprawnień. Wszystko to można oczywiście naprawić tysiącem kliknięć, ale… można też posłużyć się PowerShellem.

Oto przykład funkcji, którą się posłużyłem – szczegóły poszczególnych kroków niżej:

function Take-Over
{
 [CmdletBinding()]
 Param($path, $userName)

 Write-Verbose "Taking-Over: new owner: $newOwner path: $path"

 $fileSystemRight = [System.Security.AccessControl.FileSystemRights]::FullControl
 $accessControlType =[System.Security.AccessControl.AccessControlType]::Allow 
 if(Test-Path $path -PathType Container)
 {
 $inheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit 
 $propagationFlag = [System.Security.AccessControl.PropagationFlags]::InheritOnly
 }
 else
 {
 $inheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::None 
 $propagationFlag = [System.Security.AccessControl.PropagationFlags]::None
 }
 $ntAccount = New-Object System.Security.Principal.NTAccount($userName) 
 
 $newRule = New-Object System.Security.AccessControl.FileSystemAccessRule($ntAccount, $fileSystemRight, $inheritanceFlag, $propagationFlag, $accessControlType) 

 $objACL = Get-ACL $path 
 $objACL.SetAccessRuleProtection($False,$False)
 $objACL.SetOwner($account)
 $objACL.AddAccessRule($newRule) 

 Set-ACL $path $objACL
}

dfdfd

Po kolei:

  • $fileSystemRight = [System.Security.AccessControl.FileSystemRights]::FullControl
    tak można odwoływać sie do uprawnień zdefiniowanych w Windows
  • $accessControlType =[System.Security.AccessControl.AccessControlType]::Allow
    Uprawnienia można nadawać lub odbierać, tu wskazujemy, że uprawnienie ma być nadane
  • if(Test-Path $path -PathType Container)
    {
    $inheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit
    $propagationFlag = [System.Security.AccessControl.PropagationFlags]::InheritOnly
    }
    else
    {
    $inheritanceFlag = [System.Security.AccessControl.InheritanceFlags]::None
    $propagationFlag = [System.Security.AccessControl.PropagationFlags]::None
    }
    w przypadku folderów można zaznaczyć, że uprawnienia mają być dziedziczone na obiekty w folderze. W przypadku włączenia, można jeszcze określać co się ma dziać z aktualnie zdefiniowanymi uprawnieniami, mogą być np w całości zastąpione nowymi uprawnieniami lub dodane
  • $ntAccount = New-Object System.Security.Principal.NTAccount($userName)
    kiedy pracujesz z kontem użytkownika, to należy mieć do tego odpowiedni obiekt – sama nazwa użytkownika to może być za mało…
  • $newRule = New-Object System.Security.AccessControl.FileSystemAccessRule($ntAccount, $fileSystemRight, $inheritanceFlag, $propagationFlag, $accessControlType)
    tutaj tworzy się nowa reguła, która mówi – to konto (użytkownik) ma mieć nadane takie uprawnienie, z takimi opcjami dziedziczenia itp. Ta linijka tylko zdefiniowała obiekt pamięciowy, żadne uprawnienia nikomu nie zostały jeszcze na tym etapie nadane
  • $objACL = Get-ACL $path
    teraz ciekawa rzecz – uprawnienia pliku/katalogu trzeba najpierw przeczytać (tak jak są na dysku), zmodyfikować w pamięci i wreszcie zaaplikować na nowo. Tutaj czytamy aktualne uprawnienia…
  • $objACL.SetAccessRuleProtection($False,$False)
    … włączamy dziedziczenie uprawnień dla tego folderu z folderu nadrzędnego…
  • $objACL.SetOwner($account)
    … zmieniamy właściciela pliku folderu…
  • $objACL.AddAccessRule($newRule)
    … dodajemy uprawnienie zdefiniowane przez regułę utworzoną wcześniej…
  • Set-ACL $path $objACL
    … i na zakończenie aplikujemy/zapisujemy tak przygotowane uprawnienia do pliku/folderu na dysku

A oto jak taką funkcję wywołać, a potem usunąć folder:

$startPath = "F:\371e95404831d50c8f0f60d074f256f6"
$newOwner = "Admin"

Take-Over -Path $startPath -userName $newOwner -verbose
Get-ChildItem -Path $startPath -Recurse | foreach {Take-Over -path $_.FullName -userName $newOwner -verbose}

Remove-Item -Path $startPath -Force -Recurse

I podobnie zobaczmy co się po kolei dzieje:

  • $startPath = „F:\371e95404831d50c8f0f60d074f256f6”
    $newOwner = „Admin”
    Najpierw inicjujemy zmienne, dzięki którym łatwiej będzie w przyszłości sparametryzować ten skrypt, żeby wykorzystywać go w różnych sytuacjach
  • Take-Over -Path $startPath -userName $newOwner -verbose
    przejmujemy na własność ten jeden folder…
  • Get-ChildItem -Path $startPath -Recurse | foreach {Take-Over -path $_.FullName -userName $newOwner -verbose}
    … a następnie wszystkie jego podfoldery i podfoldery podfolderów itp.
  • Remove-Item -Path $startPath -Force -Recurse
    na zakończenie – folder jest nasz i można z nim zrobić co się chce – tutaj go usuwam 🙂

Komentarze są wyłączone

Autor: Rafał Kraik