Allg. Löschen von Ordnern bestimmer&gelöschter Besitzer

Sightus

Grand Admiral Special
Mitglied seit
01.12.2006
Beiträge
3.070
Renomée
280
  • Spinhenge ESL
  • BOINC Pentathlon 2012
  • BOINC Pentathlon 2013
  • BOINC Pentathlon 2014
  • BOINC Pentathlon 2015
  • BOINC Pentathlon 2016
  • BOINC Pentathlon 2017
  • BOINC Pentathlon 2019
  • BOINC Pentathlon 2020
  • THOR Challenge 2020
  • BOINC Pentathlon 2021
  • BOINC Pentathlon 2022
  • BOINC Pentathlon 2023
Moin,

ich habe ein paar (ca. 2.5k) Ordner samt Unterordner und Files von nicht mehr vorhandenen Usern. Werden User aus dem AD gelöscht, während diese Besitzer dieser Ordner waren, dann wird der Besitzer durch einen String wie z.B. S-1-5-21-4534759393.... ersetzt. Ich möchte nun irgendwie eine Prozedur haben (batch oder powershell), die mir alle Ordner solcher Karteileichen in einem bestimmten Pfad löscht. Von Hand geht das natürlich leicht, aber ich würde das gerne automatisieren.

Hat da jemand einen Tipp?

Danke und Gruß
 
Sowas ähnliches hab ich vor einigen Monaten für Windows Firewall-Regeln gemacht, weil MS offensichtlich unfähig ist, Windows ordentlich zu programmieren. Hier das Skript, das ich dafür verwende:
Code:
Param([switch] $dryRun
)

Function SidToUser
{
    Param(
         [Parameter(Mandatory=$true)] [string] $SID
    )

    $objSID = New-Object System.Security.Principal.SecurityIdentifier(${SID})
    try
    {
        $objUser = $objSID.Translate([System.Security.Principal.NTAccount])
        return $objUser.Value
    }
    catch
    {
        return $Null
    }
}

$FWcount=0

Write-Host "`r`nGetting firewall rules from the system ..."
$FWrules = $(Get-NetFirewallRule | Where-Object Owner -Like "S-1-5-*")

Write-Host ""
foreach($rule in ${FWrules})
{
    $sid=$rule.Owner
    if (! (SidToUser "${sid}") )
    {
        Write-Host -NoNewline "Deleting rule "
        Write-Host -NoNewline -ForegroundColor Cyan "$($(${rule}).DisplayName) "
        Write-Host -NoNewline "in group "
        Write-Host -NoNewline -ForegroundColor Cyan "$($($rule).DisplayGroup) "
        Write-Host -NoNewline "of user with unknown SID "
        Write-Host -ForegroundColor Cyan "${sid}"
        $FWcount++
        if (!$dryRun)
        {
            ${rule} | Remove-NetFirewallRule
        }
    }
}
Write-Host -NoNewline "`r`nDeleted "
Write-Host -NoNewline -ForegroundColor Cyan "${FWcount} "
Write-Host "rules.`r`n"
Start-Sleep 5
Im Prinzip müsstest du nur den Befehl Get-NetFirewallRule ersetzen durch einen Mechanismus zum Iterieren/Auflisten über/von Verzeichnisse(n). Vielleicht mit Get-Acl oder sowas, denn das bietet auch einen Owner. Ob die Funktion SidToUser auch in einem AD funktioniert, kann ich nicht beurteilen, aber ich kann mich erinnern, dass ich bei meiner Suche vor einigen Monaten auch Mechanismen fand, die den SID an einem AD testen. Und das Löschen muss dann natürlich nicht mit Remove-NetFirewallRule erfolgen, is ja klar ;).

Vielleicht genügt das erstmal als Denkanstoß :).

Grüße
Dalai
 
Zuletzt bearbeitet:
Am einfachsten wäre vermutlich eine simple Batch mit "del X:\Users\S-1-5-*" über den Task Scheduler jede Stunde, oder so, auszuführen ...
 
@BoMbY:
Nee, so einfach geht's nicht.

Längere Erklärung: Jedes Dateisystemobjekt hat irgendeinen Besitzer, und dieser Besitzer hat einen SID (Security Identifier). Üblicherweise sieht man den Besitzer in den Eigenschaften des Dateisystemobjekts (Register Sicherheit). Wenn das zugehörige Nutzerkonto existiert, sieht man dort den Namen des Kontos. Wenn ein Nutzerkonto gelöscht wird, kann dieser SID nicht mehr aufgelöst werden, so dass der SID statt des Namens als Besitzer angezeigt wird. An den Dateisystemobjekten an sich ändert sich gar nichts.

Grüße
Dalai
 
Genau, diese Ordner bleiben als "Karteileichen" zurück. Ich schaue mir das obere Script mal morgen genauer an, ist nicht so mein Steckenpferd.
 
Da es mich ebenfalls interessiert hat, wie man sowas bewerkstelligen kann, hab ich heute etwas gebastelt:
Code:
Param(
  [Parameter(Mandatory=$true)] [string] $Path,
  [switch] $dryRun
)

Function SidToUser
{
    Param(
        [Parameter(Mandatory=$true)] [string] $SID
    )

    $objSID = New-Object System.Security.Principal.SecurityIdentifier(${SID})
    try
    {
        $objUser = $objSID.Translate([System.Security.Principal.NTAccount])
        return $objUser.Value
    }
    catch
    {
        return $Null
    }
}

$Count=0

Write-Host "`r`nReading directory contents of ${Path} ..."
$FSObjectList = $(Get-ChildItem -Recurse -Path "${Path}" | Get-Acl | Where-Object Owner -Like "O:S-1-5-*")

Write-Host ""
foreach($f in ${FSObjectList})
{
    $sid=($f.Owner).SubString(2)
    if (! (SidToUser "${sid}") )
    {
        Write-Host -NoNewline "Deleting object "
        Write-Host -NoNewline -ForegroundColor Cyan "$(${f}.Path.SubString(38)) "
        Write-Host -NoNewline "of user with unknown SID "
        Write-Host -ForegroundColor Cyan "${sid}"
        $Count++
        if (!$dryRun)
        {
            ${f} | Remove-Item
        }
    }
}
Write-Host -NoNewline "`r`nDeleted "
Write-Host -NoNewline -ForegroundColor Cyan "${Count} "
Write-Host "objects.`r`n"
Nicht sonderlich schön, zumal Remove-Item fragt, wenn ganze nicht leere Verzeichnisse gelöscht werden sollen. Schnell scheint es auch nicht zu sein. Ist aber kein Wunder, denn PowerShell-Skripte hab ich bisher ziemlich wenige geschrieben, so dass da mit Sicherheit noch Optimierungspotential besteht ;D.

Du solltest beim Testen unbedingt den Schalter dryRun benutzen! Ich hatte überlegt, ob man das Skript einfach nur die Dateisystemobjekte auflisten lässt, so dass man dessen Ausgabe dann selber in der PowerShell an Remove-Item übergeben kann - kommt eben auf das Einsatzgebiet an (manuell vs. automatisiert per Taskplaner o.ä.).

Grüße
Dalai
 
Zurück
Oben Unten