0️⃣. PS – Client Cleanup Script

In diesem Beitrag möchte ich euch zeigen, wie man mit einem simplen Skript, ein wenig Ordnung in die Domäne bringt. Das Skript beinhaltet mehrere Funktionen zum löschen und bereinigen von Verzeichnissen, Logs, Updates etc.

Folgende Funktionen sind enthalten:

✅ cleanup-mgr
✅ delete-folders
✅ clear-event-logs
✅ cleanup-windows-update
✅ update-group-policy
❌ cleanup-user-profiles
✅ cleanup-temp-files
✅ cleanup-dns-cache
❌ uninstall-softwarepackage
❌ get-installedsoftware

1️⃣. Funktion zum Loggen von Nachrichten in eine Datei

PowerShell
function Log-Message {
    param (
        [string]$Message,
        [string]$Type = "INFO"
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $formattedMessage = "$timestamp [$Type] $Message"
    Write-Output $formattedMessage | Out-File -FilePath "C:\temp\log\system_cleanup.log" -Append
    # Optional: Protokoll auch zur Konsole ausgeben
    Write-Output $formattedMessage
}

Zweck:
Diese Funktion ist das Herzstück der Protokollierung im Skript. Jeder Schritt der Systembereinigung wird hierüber dokumentiert.

Funktionsweise:

  • Parameter:
    • $Message: Der eigentliche Text der Meldung.
    • $Type: Der Typ der Nachricht (Standard: „INFO“, aber auch „ERROR“ oder „WARNING“ möglich).
  • Ablauf:
    • Es wird ein Zeitstempel erstellt, der dann zusammen mit dem Nachrichtentext und dem Typ formatiert wird.
    • Der formattierte Text wird sowohl in eine Log-Datei geschrieben als auch (optional) in die Konsole ausgegeben.
  • Nutzen:
    • Durch die zentrale Log-Funktion können spätere Fehler oder unerwartete Systemzustände leichter nachvollzogen und analysiert werden.

2️⃣. Funktion zum Abrufen installierter Software

PowerShell
function get-installedsoftware {
    param (
        [string]$Name,
        [string]$Version = $null
    )
    try {
        Log-Message "Suche nach installierter Software: Name=$Name, Version=$Version"
        $package = Get-Package -Provider Programs -IncludeWindowsInstaller -Name $Name
        if ($Version) {
            $package = $package | Where-Object { $_.Version -eq $Version }
        }
        Log-Message "Gefundene Pakete: $($package.Count)"
        return $package
    } catch {
        Log-Message "Fehler beim Abrufen installierter Software: $_" "ERROR"
    }
}

Zweck:
Mit dieser Funktion können installierte Softwarepakete abgefragt werden. Das ist hilfreich, wenn man z. B. den Status oder die Version einer bestimmten Software prüfen möchte.

Funktionsweise:

  • Parameter:
    • $Name: Der Name der gesuchten Software.
    • $Version: Optional, um gezielt nach einer bestimmten Version zu suchen.
  • Ablauf:
    • Vor der Suche wird eine Log-Meldung ausgegeben.
    • Mittels Get-Package werden Pakete abgefragt, und – falls ein Versionsfilter gesetzt wurde – zusätzlich gefiltert.
    • Abschließend wird die Anzahl gefundener Pakete protokolliert und das Ergebnis zurückgegeben.
  • Nutzen:
    • Ermöglicht ein schnelles und automatisiertes Inventar der installierten Software.

3️⃣. Funktion zum Deinstallieren eines Softwarepakets

PowerShell
function uninstall-softwarepackage {
    param (
        [Microsoft.PackageManagement.Packaging.SoftwareIdentity]$Package
    )
    try {
        Log-Message "Versuche Deinstallation des Pakets: $($Package.Name)"
        if ($Package.ProviderName -eq "Programs") {
            $xml = [xml]$Package.SwidTagText
            $uninstallString = $xml.SoftwareIdentity.Meta.UninstallString
            if ($uninstallString -match 'msiexec.* /i.*') {
                $uninst = (($uninstallString -split ' ')[1] -replace '/I', '/X') + ' /qb'
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            } elseif (Test-Path -LiteralPath $uninstallString) {
                Start-Process -FilePath $uninstallString -Wait -NoNewWindow -ErrorAction Stop
            } elseif ($uninstallString -match 'msiexec.* /x.*') {
                $uninst = ($uninstallString -split ' ')[1] + ' /qb'
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            }
            Log-Message "Deinstallation erfolgreich: $($Package.Name)"
        } else {
            $Package | Uninstall-Package -ErrorAction Stop
            Log-Message "Deinstallation erfolgreich über Provider: $($Package.Name)"
        }
    } catch {
        Log-Message "Fehler bei der Deinstallation des Pakets: $_" "ERROR"
    }
}

Zweck:
Diese Funktion dient der Deinstallation eines Softwarepakets. Sie ist so aufgebaut, dass sie unterschiedliche Deinstallationsszenarien abdeckt.

Funktionsweise:

  • Parameter:
    • $Package: Ein Objekt, das Informationen über das Softwarepaket enthält.
  • Ablauf:
    • Zunächst wird über die Log-Funktion vermerkt, welches Paket deinstalliert werden soll.
    • Wird festgestellt, dass der Provider „Programs“ ist, wird der XML-Inhalt des Pakets ausgelesen, um den richtigen Deinstallationsbefehl zu ermitteln.
    • Unterschiedliche Ansätze (z. B. Ersetzen von /I zu /X bei MSI-Installationen oder direkter Aufruf eines externen Deinstallationsprogramms) werden durchlaufen.
    • Ist der Provider ein anderer, wird der generische Befehl Uninstall-Package genutzt.
    • Bei Erfolg oder im Fehlerfall wird eine entsprechende Log-Meldung ausgegeben.
  • Nutzen:
    • Sorgt für eine saubere Entfernung von Software und differenziert zwischen verschiedenen Deinstallationsmethoden.

4️⃣. Funktion zur Ausführung von Cleanmgr mit Voreinstellungen

PowerShell
function cleanup-mgr {
    try {
        Log-Message "Starte cleanup-mgr"
        $regList = @(
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\BranchCache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\D3D Shader Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Delivery Optimization Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Diagnostic Data Viewer database files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Downloaded Program Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Internet Cache Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Language Pack"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Old ChkDsk Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Recycle Bin"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\RetailDemo Offline Content"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Setup Log Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error memory dump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error minidump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Thumbnail Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\User file versions"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Defender"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Upgrade Log Files"; Key = 2 }
        )
        $keyname = 'StateFlags1337'
        foreach($key in $regList) {
            New-ItemProperty -Path $key.Pfad -Name $keyname -Value $key.Key -Type DWORD -Force | Out-Null
        }
        Start-Process "$env:SystemRoot\System32\cleanmgr.exe" -ArgumentList "/D C /verylowdisk /sagerun:1337" -WindowStyle Hidden
        Log-Message "cleanup-mgr erfolgreich abgeschlossen"
    } catch {
        Log-Message "Fehler in cleanup-mgr: $_" "ERROR"
    }
}

Zweck:
Diese Funktion nutzt den Windows „Cleanmgr“ (Datenträgerbereinigung) zur Entfernung von überflüssigen Systemdateien und Caches.

Funktionsweise:

  • Ablauf:
    • Es wird ein Array mit Registry-Pfaden definiert, die auf unterschiedliche Cache-Bereiche des Systems verweisen (z. B. Internet Cache, temporäre Dateien usw.).
    • Für jeden Eintrag wird ein spezieller Registry-Wert (StateFlags1337) mit einem definierten Wert (0, 2 etc.) gesetzt – dies signalisiert Cleanmgr, welche Bereiche bereinigt werden sollen.
    • Anschließend wird Cleanmgr mit Parametern gestartet, die den Bereinigungsprozess automatisieren (z. B. "/sagerun:1337" für die zuvor definierten Einstellungen).
    • Alle Schritte werden geloggt.
  • Nutzen:
    • Ermöglicht eine automatisierte und konsistente Bereinigung des Systems, um Speicherplatz freizugeben und die Leistung zu optimieren.

5️⃣. Funktion zum Löschen bestimmter Ordner

PowerShell
function delete-folders {
    try {
        Log-Message "Starte delete-folders"
        $chocoPath = 'C:\ProgramData\choco-cache\'
        $adobeARM = 'C:\ProgramData\Adobe\ARM\'
        if ((Get-ChildItem -Path  $chocoPath -ErrorAction SilentlyContinue | Measure-Object -ErrorAction SilentlyContinue  -Property Length -Sum).Sum /1MB -ge 100) {
            Remove-Item -Path "$chocoPath*" -Recurse -Force
            Log-Message "Chocolatey Cache gelöscht"
        }
        if (Test-Path -Path $adobeARM) {
            Remove-Item -Path "$adobeARM*" -Recurse -Force
            Log-Message "Adobe ARM-Daten gelöscht"
        }
    } catch {
        Log-Message "Fehler in delete-folders: $_" "ERROR"
    }
}

Zweck:
Mit dieser Funktion werden gezielt bestimmte Ordner gelöscht – hier etwa der Chocolatey-Cache und Adobe ARM-Daten.

Funktionsweise:

  • Ablauf:
    • Zunächst wird der Pfad des Chocolatey-Caches überprüft. Liegt dessen Größe über einem definierten Schwellenwert (hier 100 MB), wird der gesamte Inhalt gelöscht.
    • Ebenso wird der Adobe ARM-Pfad überprüft und – falls vorhanden – geleert.
    • Beide Aktionen werden protokolliert.
  • Nutzen:
    • Reduziert den unnötig belegten Speicherplatz durch veraltete oder temporäre Cache-Daten.

6️⃣. Funktion zur Bereinigung von Event-Logs

PowerShell
function clear-event-logs {
    try {
        Log-Message "Starte clear-event-logs"
        $threeMonthsAgo = (Get-Date).AddMonths(-4)

        # Liste aller Event-Logs
        $eventLogs = Get-WinEvent -ListLog *  | Where { $_.RecordCount -gt 0}

        foreach ($log in $eventLogs) {
            $logName = $log.LogName

            try {
                # Prüfen, wann das letzte Ereignis erstellt wurde
                $latestEvent = Get-WinEvent -LogName $logName -MaxEvents 1 -ErrorAction Stop
                if ($latestEvent) {
                    $latestEventTime = $latestEvent.TimeCreated
                    if ($latestEventTime -lt $threeMonthsAgo) {
                        # Log löschen, wenn das letzte Ereignis älter als 3 Monate ist
                        Clear-EventLog -LogName $logName
                        Log-Message "Event-Log $logName erfolgreich bereinigt"
                    }
                }
            } catch {
                # Wenn keine Ereignisse gefunden werden, überspringen
                if ($_.Exception -is [System.Management.Automation.RuntimeException]) {
                    Log-Message "Keine Ereignisse im Log $logName gefunden oder Fehler beim Abrufen der Ereignisse: $_" "WARNING"
                } else {
                    Log-Message "Fehler beim Abrufen von Ereignissen im Log $logName : $_" "ERROR"
                }
            }
        }
    } catch {
        Log-Message "Fehler in clear-event-logs: $_" "ERROR"
    }
}

Zweck:
Event-Logs können über längere Zeiträume wachsen und unnötig Speicher belegen. Diese Funktion löscht jene Logs, die über einen definierten Zeitraum (hier: älter als ca. 4 Monate) nicht aktualisiert wurden.

Funktionsweise:

  • Ablauf:
    • Es wird ein Schwellenwert-Datum berechnet, das angibt, ab wann Logs als „alt“ gelten.
    • Mit Get-WinEvent werden alle Event-Logs abgefragt, die Einträge enthalten.
    • Für jedes Log wird das Datum des letzten Eintrags überprüft.
    • Sind die Logs „veraltet“, wird Clear-EventLog aufgerufen, um den Inhalt zu löschen.
    • Besondere Fehlerfälle (z. B. wenn keine Ereignisse vorhanden sind) werden separat behandelt und geloggt.
  • Nutzen:
    • Sorgt dafür, dass alte und nicht mehr relevante Log-Daten entfernt werden – ein wichtiger Schritt zur Systemwartung und zur Einsparung von Festplattenspeicher.

7️⃣. Funktion zur Bereinigung des Windows Update Caches

PowerShell
function cleanup-windows-update {
    try {
        Log-Message "Starte cleanup-windows-update"
        net stop wuauserv
        Remove-Item -LiteralPath "C:\Windows\SoftwareDistribution\*" -Recurse -Force
        net start wuauserv
        Log-Message "Windows Update Cache erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-windows-update: $_" "ERROR"
    }
}

Zweck:
Diese Funktion räumt den Windows Update-Cache auf, der sich mit der Zeit ansammeln und potenziell zu fehlerhaften Update-Vorgängen führen kann.

Funktionsweise:

  • Ablauf:
    • Der Windows Update Service (wuauserv) wird gestoppt, um sicherzustellen, dass keine Dateien in Benutzung sind.
    • Der Inhalt des Ordners C:\Windows\SoftwareDistribution\* wird gelöscht.
    • Anschließend wird der Dienst wieder gestartet.
    • Alle Schritte werden im Log dokumentiert.
  • Nutzen:
    • Hilft bei der Behebung von Update-Problemen und stellt sicher, dass der Update-Cache stets auf dem neuesten Stand ist.

8️⃣. Funktion zur Aktualisierung von Gruppenrichtlinien

PowerShell
function update-group-policy {
    try {
        Log-Message "Starte update-group-policy"
        gpupdate /force
        Log-Message "Gruppenrichtlinien erfolgreich aktualisiert"
    } catch {
        Log-Message "Fehler in update-group-policy: $_" "ERROR"
    }
}

Zweck:
Mit dieser Funktion werden Gruppenrichtlinien sofort aktualisiert, sodass alle Änderungen unverzüglich wirksam werden.

Funktionsweise:

  • Ablauf:
    • Der Befehl gpupdate /force wird ausgeführt, um alle Gruppenrichtlinien zu aktualisieren.
    • Erfolgreiche Aktualisierungen sowie etwaige Fehler werden geloggt.
  • Nutzen:
    • Stellt sicher, dass alle aktuellen Richtlinien (z. B. Sicherheits- und Konfigurationsvorgaben) auf dem System aktiv sind.

9️⃣. Funktion zur Bereinigung alter Benutzerprofile

PowerShell
function cleanup-user-profiles {
    try {
        Log-Message "Starte cleanup-user-profiles"
        $profilesToDelete = Get-WmiObject -Class Win32_UserProfile | Where-Object {
            $_.Special -eq $false -and $_.LastUseTime -lt ((Get-Date).AddDays(-6000)).ToFileTime()
        }

        foreach ($profile in $profilesToDelete) {
            Remove-WmiObject -InputObject $profile
            Log-Message "Benutzerprofil gelöscht: $($profile.LocalPath)"
        }

        Log-Message "Alte Benutzerprofile erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-user-profiles: $_" "ERROR"
    }
}

Zweck:
Diese Funktion entfernt alte Benutzerprofile, die seit langer Zeit nicht mehr verwendet wurden – etwa von ehemaligen Mitarbeitern oder inaktiven Nutzern.

Funktionsweise:

  • Ablauf:
    • Mithilfe von Get-WmiObject und der Klasse Win32_UserProfile werden alle Benutzerprofile abgefragt.
    • Es werden nur Profile berücksichtigt, die nicht als „Special“ markiert sind und deren letzter Nutzungszeitpunkt (LastUseTime) vor einem bestimmten Datum liegt.
    • Jedes gefundene Profil wird mittels Remove-WmiObject gelöscht.
    • Jeder Löschvorgang wird protokolliert.
  • Nutzen:
    • Bereinigt das System von überflüssigen Benutzerprofilen, was zu einer verbesserten Systemleistung und einer geringeren Fragmentierung der Benutzerverzeichnisse führt.

1️⃣0️⃣. Funktion zur Bereinigung temporärer Dateien

PowerShell
function cleanup-temp-files {
    try {
        Log-Message "Starte cleanup-temp-files"
        Remove-Item -LiteralPath "C:\Windows\Temp\*" -Recurse -Force
        Remove-Item -LiteralPath "$env:TEMP\*" -Recurse -Force
        Log-Message "Temporäre Dateien erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-temp-files: $_" "ERROR"
    }
}

Zweck:
Diese Funktion löscht temporäre Dateien, die sich sowohl im Windows-Temp-Ordner als auch im benutzerspezifischen Temp-Verzeichnis angesammelt haben.

Funktionsweise:

  • Ablauf:
    • Es werden die Inhalte des Systemordners C:\Windows\Temp\* sowie des benutzerspezifischen Temp-Ordners ($env:TEMP\*) rekursiv gelöscht.
    • Auch hier sorgt die Fehlerbehandlung dafür, dass eventuelle Probleme im Löschvorgang geloggt werden.
  • Nutzen:
    • Durch das Entfernen von temporären Dateien wird unnötig belegter Speicher freigegeben und das System bleibt „sauber“, was wiederum die Performance verbessert.

1️⃣1️⃣. Funktion zur Bereinigung des DNS-Caches

PowerShell
function cleanup-dns-cache {
    try {
        Log-Message "Starte cleanup-dns-cache"
        Clear-DnsClientCache
        Log-Message "DNS-Cache erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-dns-cache: $_" "ERROR"
    }
}

Zweck:
Mit dieser Funktion wird der DNS-Cache geleert, um veraltete DNS-Einträge zu entfernen und so mögliche Netzwerkprobleme (z. B. falsche Namensauflösung) zu vermeiden.

Funktionsweise:

  • Ablauf:
    • Der Befehl Clear-DnsClientCache wird ausgeführt, um alle zwischengespeicherten DNS-Einträge zu löschen.
    • Erfolg oder Fehler werden ebenfalls protokolliert.
  • Nutzen:
    • Hilft bei der Behebung von Netzwerkproblemen, wenn DNS-Einträge aktualisiert wurden, aber der alte Cache weiterhin verwendet wird.

1️⃣2️⃣. Hauptfunktion zur Reinigung des Systems

PowerShell
function cleanup {
    try {
        Log-Message "Starte Systembereinigung"
        cleanup-mgr
        delete-folders
        clear-event-logs
        cleanup-windows-update
        update-group-policy
        #cleanup-user-profiles
        cleanup-temp-files
        cleanup-dns-cache
        Log-Message "Systembereinigung erfolgreich abgeschlossen"
    } catch {
        Log-Message "Fehler in cleanup: $_" "ERROR"
    }
}
# Ausführung der Systembereinigung
cleanup

Zweck:
Diese zentrale Funktion orchestriert die Ausführung aller einzelnen Bereinigungsroutinen, um eine umfassende Systemwartung in einem Durchgang zu ermöglichen.

Funktionsweise:

  • Ablauf:
    • Zu Beginn wird eine Log-Meldung ausgegeben, die den Start der Systembereinigung signalisiert.
    • Nacheinander werden alle vorher definierten Funktionen (wie cleanup-mgr, delete-folders, clear-event-logs, cleanup-windows-update, update-group-policy, cleanup-temp-files und cleanup-dns-cache) aufgerufen.
    • (Hinweis: Die Funktion cleanup-user-profiles ist auskommentiert – je nach Bedarf kann sie aktiviert werden.)
    • Abschließend wird ein Log-Eintrag erstellt, der den erfolgreichen Abschluss der Bereinigung bestätigt.
  • Nutzen:
    • Sorgt für einen strukturierten und automatisierten Ablauf, der alle wichtigen Wartungsaufgaben zusammenfasst.

Das Komplette Skript sieht dann wie folgt aus:

PowerShell
# Funktion zum Loggen von Nachrichten in eine Datei
function Log-Message {
    param (
        [string]$Message,
        [string]$Type = "INFO"
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $formattedMessage = "$timestamp [$Type] $Message"
    Write-Output $formattedMessage | Out-File -FilePath "C:\temp\log\system_cleanup.log" -Append
    # Optional: Protokoll auch zur Konsole ausgeben
    Write-Output $formattedMessage
}

# Funktion zum Abrufen installierter Software
function get-installedsoftware {
    param (
        [string]$Name,
        [string]$Version = $null
    )
    try {
        Log-Message "Suche nach installierter Software: Name=$Name, Version=$Version"
        $package = Get-Package -Provider Programs -IncludeWindowsInstaller -Name $Name
        if ($Version) {
            $package = $package | Where-Object { $_.Version -eq $Version }
        }
        Log-Message "Gefundene Pakete: $($package.Count)"
        return $package
    } catch {
        Log-Message "Fehler beim Abrufen installierter Software: $_" "ERROR"
    }
}

# Funktion zum Deinstallieren eines Softwarepakets
function uninstall-softwarepackage {
    param (
        [Microsoft.PackageManagement.Packaging.SoftwareIdentity]$Package
    )
    try {
        Log-Message "Versuche Deinstallation des Pakets: $($Package.Name)"
        if ($Package.ProviderName -eq "Programs") {
            $xml = [xml]$Package.SwidTagText
            $uninstallString = $xml.SoftwareIdentity.Meta.UninstallString
            if ($uninstallString -match 'msiexec.* /i.*') {
                $uninst = (($uninstallString -split ' ')[1] -replace '/I', '/X') + ' /qb'
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            } elseif (Test-Path -LiteralPath $uninstallString) {
                Start-Process -FilePath $uninstallString -Wait -NoNewWindow -ErrorAction Stop
            } elseif ($uninstallString -match 'msiexec.* /x.*') {
                $uninst = ($uninstallString -split ' ')[1] + ' /qb'
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            }
            Log-Message "Deinstallation erfolgreich: $($Package.Name)"
        } else {
            $Package | Uninstall-Package -ErrorAction Stop
            Log-Message "Deinstallation erfolgreich über Provider: $($Package.Name)"
        }
    } catch {
        Log-Message "Fehler bei der Deinstallation des Pakets: $_" "ERROR"
    }
}

# Funktion zur Ausführung von Cleanmgr mit Voreinstellungen
function cleanup-mgr {
    try {
        Log-Message "Starte cleanup-mgr"
        $regList = @(
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\BranchCache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\D3D Shader Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Delivery Optimization Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Diagnostic Data Viewer database files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Downloaded Program Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Internet Cache Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Language Pack"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Old ChkDsk Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Recycle Bin"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\RetailDemo Offline Content"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Setup Log Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error memory dump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error minidump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Thumbnail Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\User file versions"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Defender"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Upgrade Log Files"; Key = 2 }
        )
        $keyname = 'StateFlags1337'
        foreach($key in $regList) {
            New-ItemProperty -Path $key.Pfad -Name $keyname -Value $key.Key -Type DWORD -Force | Out-Null
        }
        Start-Process "$env:SystemRoot\System32\cleanmgr.exe" -ArgumentList "/D C /verylowdisk /sagerun:1337" -WindowStyle Hidden
        Log-Message "cleanup-mgr erfolgreich abgeschlossen"
    } catch {
        Log-Message "Fehler in cleanup-mgr: $_" "ERROR"
    }
}

# Funktion zum Löschen bestimmter Ordner
function delete-folders {
    try {
        Log-Message "Starte delete-folders"
        $chocoPath = 'C:\ProgramData\choco-cache\'
        $adobeARM = 'C:\ProgramData\Adobe\ARM\'
        if ((Get-ChildItem -Path  $chocoPath -ErrorAction SilentlyContinue | Measure-Object -ErrorAction SilentlyContinue  -Property Length -Sum).Sum /1MB -ge 100) {
            Remove-Item -Path "$chocoPath*" -Recurse -Force
            Log-Message "Chocolatey Cache gelöscht"
        }
        if (Test-Path -Path $adobeARM) {
            Remove-Item -Path "$adobeARM*" -Recurse -Force
            Log-Message "Adobe ARM-Daten gelöscht"
        }
    } catch {
        Log-Message "Fehler in delete-folders: $_" "ERROR"
    }
}

# Funktion zur Bereinigung von Event-Logs
function clear-event-logs {
    try {
        Log-Message "Starte clear-event-logs"
        $threeMonthsAgo = (Get-Date).AddMonths(-4)

        # Liste aller Event-Logs
        $eventLogs = Get-WinEvent -ListLog *  | Where { $_.RecordCount -gt 0}

        foreach ($log in $eventLogs) {
            $logName = $log.LogName

            try {
                # Prüfen, wann das letzte Ereignis erstellt wurde
                $latestEvent = Get-WinEvent -LogName $logName -MaxEvents 1 -ErrorAction Stop
                if ($latestEvent) {
                    $latestEventTime = $latestEvent.TimeCreated
                    if ($latestEventTime -lt $threeMonthsAgo) {
                        # Log löschen, wenn das letzte Ereignis älter als 3 Monate ist
                        Clear-EventLog -LogName $logName
                        Log-Message "Event-Log $logName erfolgreich bereinigt"
                    }
                }
            } catch {
                # Wenn keine Ereignisse gefunden werden, überspringen
                if ($_.Exception -is [System.Management.Automation.RuntimeException]) {
                    Log-Message "Keine Ereignisse im Log $logName gefunden oder Fehler beim Abrufen der Ereignisse: $_" "WARNING"
                } else {
                    Log-Message "Fehler beim Abrufen von Ereignissen im Log $logName : $_" "ERROR"
                }
            }
        }
    } catch {
        Log-Message "Fehler in clear-event-logs: $_" "ERROR"
    }
}



# Funktion zur Bereinigung des Windows Update Caches
function cleanup-windows-update {
    try {
        Log-Message "Starte cleanup-windows-update"
        net stop wuauserv
        Remove-Item -LiteralPath "C:\Windows\SoftwareDistribution\*" -Recurse -Force
        net start wuauserv
        Log-Message "Windows Update Cache erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-windows-update: $_" "ERROR"
    }
}

# Funktion zur Aktualisierung von Gruppenrichtlinien
function update-group-policy {
    try {
        Log-Message "Starte update-group-policy"
        gpupdate /force
        Log-Message "Gruppenrichtlinien erfolgreich aktualisiert"
    } catch {
        Log-Message "Fehler in update-group-policy: $_" "ERROR"
    }
}

# Funktion zur Bereinigung alter Benutzerprofile
function cleanup-user-profiles {
    try {
        Log-Message "Starte cleanup-user-profiles"
        $profilesToDelete = Get-WmiObject -Class Win32_UserProfile | Where-Object {
            $_.Special -eq $false -and $_.LastUseTime -lt ((Get-Date).AddDays(-6000)).ToFileTime()
        }

        foreach ($profile in $profilesToDelete) {
            Remove-WmiObject -InputObject $profile
            Log-Message "Benutzerprofil gelöscht: $($profile.LocalPath)"
        }

        Log-Message "Alte Benutzerprofile erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-user-profiles: $_" "ERROR"
    }
}

# Funktion zur Bereinigung temporärer Dateien
function cleanup-temp-files {
    try {
        Log-Message "Starte cleanup-temp-files"
        Remove-Item -LiteralPath "C:\Windows\Temp\*" -Recurse -Force
        Remove-Item -LiteralPath "$env:TEMP\*" -Recurse -Force
        Log-Message "Temporäre Dateien erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-temp-files: $_" "ERROR"
    }
}

# Funktion zur Bereinigung des DNS-Caches
function cleanup-dns-cache {
    try {
        Log-Message "Starte cleanup-dns-cache"
        Clear-DnsClientCache
        Log-Message "DNS-Cache erfolgreich bereinigt"
    } catch {
        Log-Message "Fehler in cleanup-dns-cache: $_" "ERROR"
    }
}

# Hauptfunktion zur Reinigung des Systems
function cleanup {
    try {
        Log-Message "Starte Systembereinigung"
        cleanup-mgr
        delete-folders
        clear-event-logs
        cleanup-windows-update
        update-group-policy
        #cleanup-user-profiles
        cleanup-temp-files
        cleanup-dns-cache
        Log-Message "Systembereinigung erfolgreich abgeschlossen"
    } catch {
        Log-Message "Fehler in cleanup: $_" "ERROR"
    }
}

# Ausführung der Systembereinigung
cleanup

Wenn man das Ganze noch etwas aufhübscht, die comment-based Hilfe hinzufügt und das logging erweitert, erhält man ein gutes und leicht verständliches Skript.

PowerShell
<#
.SYNOPSIS
    System-Cleanup-Skript für Windows-Systeme.
    
.DESCRIPTION
    Dieses Skript führt verschiedene Reinigungsoperationen auf einem Windows-System durch,
    einschließlich Entfernung temporärer Dateien, Bereinigung des Disk Space Manager,
    Löschen des Windows Update-Caches, Bereinigung von Event-Logs und mehr.
    
.NOTES
    Dateiname: system_cleanup.ps1
    Autor: Ismahiil Ahmed
    Version: 1.1
    Datum: 2025-03-11
    Voraussetzungen: PowerShell 5.1 oder höher, Administratorrechte
    
.EXAMPLE
    .\system_cleanup.ps1
    
    Führt alle Bereinigungsoperationen durch.
#>

# Stellen Sie sicher, dass das Protokollverzeichnis existiert
$logPath = "C:\temp\log"
if (-not (Test-Path -Path $logPath)) {
    New-Item -Path $logPath -ItemType Directory -Force | Out-Null
}

<#
.SYNOPSIS
    Protokolliert Nachrichten in eine Datei.
    
.DESCRIPTION
    Protokolliert Nachrichten mit Zeitstempel und Typ in eine Protokolldatei
    und gibt sie optional auch in der Konsole aus.
    
.PARAMETER Message
    Die zu protokollierende Nachricht.
    
.PARAMETER Type
    Der Nachrichtentyp (z.B. INFO, WARNING, ERROR).
    
.EXAMPLE
    Log-Message "Operation abgeschlossen" "INFO"
    
    Protokolliert "Operation abgeschlossen" als INFO-Nachricht.
#>
function Log-Message {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Message,
        
        [Parameter(Mandatory = $false, Position = 1)]
        [ValidateSet("INFO", "WARNING", "ERROR", "SUCCESS")]
        [string]$Type = "INFO"
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $formattedMessage = "$timestamp [$Type] $Message"
    
    # Stellen Sie sicher, dass die Protokolldatei existiert
    $logFile = "C:\temp\log\system_cleanup.log"
    if (-not (Test-Path -Path $logFile)) {
        New-Item -Path $logFile -ItemType File -Force | Out-Null
    }
    
    Add-Content -Path $logFile -Value $formattedMessage
    
    # Farbcodierung für Konsolenausgabe
    switch ($Type) {
        "INFO" { Write-Host $formattedMessage -ForegroundColor Cyan }
        "WARNING" { Write-Host $formattedMessage -ForegroundColor Yellow }
        "ERROR" { Write-Host $formattedMessage -ForegroundColor Red }
        "SUCCESS" { Write-Host $formattedMessage -ForegroundColor Green }
        default { Write-Host $formattedMessage }
    }
}

<#
.SYNOPSIS
    Ruft installierte Software ab.
    
.DESCRIPTION
    Sucht nach installierter Software anhand des Namens und optional der Version.
    
.PARAMETER Name
    Der Name der zu suchenden Software. Unterstützt Platzhalter (*).
    
.PARAMETER Version
    Optional: Die spezifische Version der zu suchenden Software.
    
.EXAMPLE
    get-installedsoftware "Adobe*"
    
    Gibt alle installierten Adobe-Softwarepakete zurück.
    
.EXAMPLE
    get-installedsoftware "Microsoft Office" "16.0.12345.67890"
    
    Gibt Microsoft Office mit der angegebenen Version zurück, falls installiert.
    
.OUTPUTS
    Microsoft.PackageManagement.Packaging.SoftwareIdentity
    Ein oder mehrere Softwareidentitätsobjekte, die der Suche entsprechen.
#>
function get-installedsoftware {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Name,
        
        [Parameter(Mandatory = $false, Position = 1)]
        [string]$Version = $null
    )
    
    try {
        Log-Message "Suche nach installierter Software: Name=$Name, Version=$Version"
        
        # Hole alle Pakete, die dem Namen entsprechen
        $packages = Get-Package -Provider Programs -IncludeWindowsInstaller -Name $Name -ErrorAction Stop
        
        # Filtere nach Version, falls angegeben
        if ($Version) {
            $packages = $packages | Where-Object { $_.Version -eq $Version }
        }
        
        $count = if ($packages) { $packages.Count } else { 0 }
        Log-Message "Gefundene Pakete: $count"
        
        return $packages
    } 
    catch {
        Log-Message "Fehler beim Abrufen installierter Software: $_" "ERROR"
        return $null
    }
}

<#
.SYNOPSIS
    Deinstalliert ein Softwarepaket.
    
.DESCRIPTION
    Deinstalliert ein Softwarepaket basierend auf dem übergebenen Paketobjekt.
    Unterstützt verschiedene Deinstallationsmethoden je nach Pakettyp.
    
.PARAMETER Package
    Das zu deinstallierende Softwarepaket (SoftwareIdentity-Objekt).
    
.EXAMPLE
    $office = get-installedsoftware "Microsoft Office"
    uninstall-softwarepackage $office
    
    Deinstalliert Microsoft Office.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
#>
function uninstall-softwarepackage {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [Microsoft.PackageManagement.Packaging.SoftwareIdentity]$Package
    )
    
    try {
        Log-Message "Versuche Deinstallation des Pakets: $($Package.Name) (Version: $($Package.Version))"
        
        # Prüfe, ob es sich um ein Programm handelt
        if ($Package.ProviderName -eq "Programs") {
            # Extrahiere Deinstallationsinformationen aus SWID-Tag
            $xml = [xml]$Package.SwidTagText
            $uninstallString = $xml.SoftwareIdentity.Meta.UninstallString
            
            Log-Message "Deinstallationsstring: $uninstallString" "INFO"
            
            # Verarbeite je nach Art des Deinstallationsstrings
            if ($uninstallString -match 'msiexec.* /[iI].*') {
                # MSI-Deinstallation (ersetze /I durch /X für Deinstallation)
                $uninst = (($uninstallString -split ' ')[1] -replace '/[iI]', '/X') + ' /qb'
                Log-Message "Führe MSI-Deinstallation aus: msiexec.exe $uninst"
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            } 
            elseif ($uninstallString -match 'msiexec.* /[xX].*') {
                # MSI-Deinstallation (bereits mit /X)
                $uninst = ($uninstallString -split ' ')[1] + ' /qb'
                Log-Message "Führe MSI-Deinstallation aus: msiexec.exe $uninst"
                Start-Process msiexec.exe -ArgumentList $uninst -Wait -NoNewWindow -ErrorAction Stop
            }
            elseif (Test-Path -LiteralPath $uninstallString -ErrorAction SilentlyContinue) {
                # Ausführbare Deinstallationsdatei
                Log-Message "Führe Deinstallationsprogramm aus: $uninstallString"
                Start-Process -FilePath $uninstallString -Wait -NoNewWindow -ErrorAction Stop
            }
            else {
                # Versuche, den Deinstallationsstring direkt auszuführen
                Log-Message "Versuche direkten Aufruf des Deinstallationsstrings"
                Invoke-Expression $uninstallString
            }
            
            Log-Message "Deinstallation erfolgreich: $($Package.Name)" "SUCCESS"
        } 
        else {
            # Für andere Provider (z.B. PowerShellGet, Chocolatey)
            Log-Message "Deinstalliere über Paketprovider: $($Package.ProviderName)"
            $Package | Uninstall-Package -Force -ErrorAction Stop
            Log-Message "Deinstallation erfolgreich über Provider: $($Package.Name)" "SUCCESS"
        }
    } 
    catch {
        Log-Message "Fehler bei der Deinstallation des Pakets: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Führt den Windows Disk Cleanup Manager mit vordefinierten Einstellungen aus.
    
.DESCRIPTION
    Konfiguriert und startet den Windows Disk Cleanup Manager (cleanmgr.exe) mit 
    vordefinierten Einstellungen zur Bereinigung verschiedener Systemdateien.
    
.EXAMPLE
    cleanup-mgr
    
    Führt den Disk Cleanup Manager mit den vordefinierten Einstellungen aus.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
    Ein Wert von 2 bedeutet, dass diese Kategorie zur Bereinigung ausgewählt wird.
#>
function cleanup-mgr {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte cleanup-mgr"
        
        # Definiere die zu bereinigenden Kategorien
        $regList = @(
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\BranchCache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\D3D Shader Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Delivery Optimization Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Diagnostic Data Viewer database files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Downloaded Program Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Internet Cache Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Language Pack"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Old ChkDsk Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Recycle Bin"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\RetailDemo Offline Content"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Setup Log Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error memory dump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error minidump files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Files"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Thumbnail Cache"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup"; Key = 2 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\User file versions"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Defender"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting Files"; Key = 0 },
            @{ Pfad = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Upgrade Log Files"; Key = 2 }
        )
        
        # Verwende einen eindeutigen Namen für den Cleanup-Lauf
        $keyname = 'StateFlags1337'
        
        # Setze die Registry-Einträge für jede Kategorie
        foreach($key in $regList) {
            # Prüfe, ob Registry-Pfad existiert, und erstelle ihn ggf.
            if (-not (Test-Path -Path $key.Pfad)) {
                New-Item -Path $key.Pfad -Force | Out-Null
            }
            
            # Setze oder aktualisiere den Registry-Wert
            New-ItemProperty -Path $key.Pfad -Name $keyname -Value $key.Key -Type DWORD -Force | Out-Null
        }
        
        # Starte den Disk Cleanup Manager
        Log-Message "Starte cleanmgr.exe mit vordefinierten Einstellungen"
        Start-Process -FilePath "$env:SystemRoot\System32\cleanmgr.exe" -ArgumentList "/D C /verylowdisk /sagerun:1337" -WindowStyle Hidden -Wait
        
        Log-Message "cleanup-mgr erfolgreich abgeschlossen" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in cleanup-mgr: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Löscht spezifische Cache-Ordner und temporäre Dateien.
    
.DESCRIPTION
    Löscht den Chocolatey-Cache und Adobe ARM-Daten, wenn sie vorhanden sind
    und bestimmte Größenbedingungen erfüllen.
    
.EXAMPLE
    delete-folders
    
    Löscht Chocolatey-Cache und Adobe ARM-Daten, falls sie existieren.
#>
function delete-folders {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte delete-folders"
        
        # Definiere zu prüfende Pfade
        $foldersToCheck = @(
            @{
                Path = 'C:\ProgramData\choco-cache\';
                Name = "Chocolatey Cache";
                SizeThreshold = 100; # in MB
                CheckSize = $true;
            },
            @{
                Path = 'C:\ProgramData\Adobe\ARM\';
                Name = "Adobe ARM-Daten";
                CheckSize = $false;
            }
        )
        
        # Prüfe und lösche jeden Ordner gemäß den Bedingungen
        foreach ($folder in $foldersToCheck) {
            if (Test-Path -Path $folder.Path) {
                $shouldDelete = $true
                
                # Prüfe Größe, falls erforderlich
                if ($folder.CheckSize) {
                    $size = (Get-ChildItem -Path $folder.Path -Recurse -ErrorAction SilentlyContinue | 
                            Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB
                    
                    if ($size -lt $folder.SizeThreshold) {
                        Log-Message "$($folder.Name) ist kleiner als $($folder.SizeThreshold) MB (aktuell: $([math]::Round($size, 2)) MB), wird übersprungen" "INFO"
                        $shouldDelete = $false
                    }
                    else {
                        Log-Message "$($folder.Name) hat die Größe von $([math]::Round($size, 2)) MB" "INFO"
                    }
                }
                
                # Lösche den Ordner, wenn die Bedingungen erfüllt sind
                if ($shouldDelete) {
                    Remove-Item -Path "$($folder.Path)*" -Recurse -Force -ErrorAction Stop
                    Log-Message "$($folder.Name) erfolgreich gelöscht" "SUCCESS"
                }
            }
            else {
                Log-Message "$($folder.Name) nicht gefunden, Überspringen" "INFO"
            }
        }
        
        Log-Message "delete-folders abgeschlossen" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in delete-folders: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Bereinigt Windows-Event-Logs, die älter als ein bestimmter Zeitraum sind.
    
.DESCRIPTION
    Identifiziert Event-Logs, deren letzter Eintrag älter als vier Monate ist,
    und löscht deren Inhalt.
    
.EXAMPLE
    clear-event-logs
    
    Bereinigt alle Event-Logs, deren letzte Einträge älter als vier Monate sind.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
#>
function clear-event-logs {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte clear-event-logs"
        
        # Definiere den Grenzwert (vier Monate zurück)
        $threeMonthsAgo = (Get-Date).AddMonths(-4)
        Log-Message "Lösche Event-Logs mit Einträgen älter als $($threeMonthsAgo.ToString('yyyy-MM-dd'))" "INFO"
        
        # Hole alle Event-Logs mit Einträgen
        $eventLogs = Get-WinEvent -ListLog * -ErrorAction SilentlyContinue | 
                      Where-Object { $_.RecordCount -gt 0 -and $_.IsEnabled -and $_.IsLogFull -eq $false }
        
        $clearedCount = 0
        $skippedCount = 0
        $errorCount = 0
        
        foreach ($log in $eventLogs) {
            $logName = $log.LogName
            
            try {
                # Prüfe, wann das letzte Ereignis erstellt wurde
                $latestEvent = Get-WinEvent -LogName $logName -MaxEvents 1 -ErrorAction Stop
                
                if ($latestEvent) {
                    $latestEventTime = $latestEvent.TimeCreated
                    
                    if ($latestEventTime -lt $threeMonthsAgo) {
                        # Log löschen, wenn das letzte Ereignis älter als die Grenze ist
                        [System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog($logName)
                        $clearedCount++
                        Log-Message "Event-Log '$logName' erfolgreich bereinigt (letzter Eintrag: $($latestEventTime.ToString('yyyy-MM-dd')))" "SUCCESS"
                    }
                    else {
                        $skippedCount++
                        Log-Message "Event-Log '$logName' übersprungen (letzter Eintrag: $($latestEventTime.ToString('yyyy-MM-dd')))" "INFO"
                    }
                }
            } 
            catch {
                $errorCount++
                # Wenn keine Ereignisse gefunden werden oder andere Fehler auftreten
                if ($_.Exception -is [System.Management.Automation.RuntimeException] -or 
                    $_.Exception.Message -match "No events") {
                    Log-Message "Keine Ereignisse im Log '$logName' gefunden oder unzureichende Berechtigungen" "WARNING"
                } 
                else {
                    Log-Message "Fehler beim Bearbeiten des Logs '$logName': $_" "ERROR"
                }
            }
        }
        
        Log-Message "Event-Log-Bereinigung abgeschlossen: $clearedCount gelöscht, $skippedCount übersprungen, $errorCount Fehler" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in clear-event-logs: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Bereinigt den Windows Update Cache.
    
.DESCRIPTION
    Stoppt den Windows Update-Dienst, löscht den Inhalt des SoftwareDistribution-Ordners
    und startet den Dienst wieder.
    
.EXAMPLE
    cleanup-windows-update
    
    Bereinigt den Windows Update Cache.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
#>
function cleanup-windows-update {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte cleanup-windows-update"
        
        # Prüfe Größe des Update-Caches vor der Bereinigung
        $updateCachePath = "C:\Windows\SoftwareDistribution"
        $sizeBefore = 0
        
        if (Test-Path -Path $updateCachePath) {
            $sizeBefore = (Get-ChildItem -Path $updateCachePath -Recurse -ErrorAction SilentlyContinue | 
                          Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB
            Log-Message "Windows Update Cache-Größe vor Bereinigung: $([math]::Round($sizeBefore, 2)) MB" "INFO"
        }
        
        # Stoppe den Windows Update-Dienst
        Log-Message "Stoppe Windows Update-Dienst" "INFO"
        Stop-Service -Name wuauserv -Force -ErrorAction Stop
        
        # Lösche den Inhalt des SoftwareDistribution-Ordners
        if (Test-Path -Path $updateCachePath) {
            Remove-Item -LiteralPath "$updateCachePath\*" -Recurse -Force -ErrorAction SilentlyContinue
            Log-Message "Windows Update Cache-Dateien gelöscht" "SUCCESS"
        }
        
        # Starte den Windows Update-Dienst wieder
        Log-Message "Starte Windows Update-Dienst" "INFO"
        Start-Service -Name wuauserv -ErrorAction Stop
        
        # Prüfe Größe nach der Bereinigung
        $sizeAfter = 0
        if (Test-Path -Path $updateCachePath) {
            $sizeAfter = (Get-ChildItem -Path $updateCachePath -Recurse -ErrorAction SilentlyContinue | 
                         Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB
            
            $savedSpace = $sizeBefore - $sizeAfter
            Log-Message "Windows Update Cache-Größe nach Bereinigung: $([math]::Round($sizeAfter, 2)) MB (gespart: $([math]::Round($savedSpace, 2)) MB)" "SUCCESS"
        }
        
        Log-Message "Windows Update Cache erfolgreich bereinigt" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in cleanup-windows-update: $_" "ERROR"
        
        # Versuche, den Windows Update-Dienst zu starten, falls er gestoppt wurde
        try {
            Start-Service -Name wuauserv -ErrorAction SilentlyContinue
        } 
        catch {
            Log-Message "Konnte Windows Update-Dienst nicht neu starten: $_" "ERROR"
        }
    }
}

<#
.SYNOPSIS
    Aktualisiert Gruppenrichtlinien.
    
.DESCRIPTION
    Führt eine Aktualisierung der Gruppenrichtlinien auf dem Computer durch.
    
.EXAMPLE
    update-group-policy
    
    Aktualisiert Gruppenrichtlinien mit Force-Option.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
#>
function update-group-policy {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte update-group-policy"
        
        # Führe gpupdate mit Force-Option aus
        $process = Start-Process -FilePath "gpupdate.exe" -ArgumentList "/force" -Wait -PassThru -NoNewWindow
        
        # Prüfe Exit-Code
        if ($process.ExitCode -eq 0) {
            Log-Message "Gruppenrichtlinien erfolgreich aktualisiert" "SUCCESS"
        } 
        else {
            Log-Message "Gruppenrichtlinien-Update abgeschlossen mit Exit-Code $($process.ExitCode)" "WARNING"
        }
    } 
    catch {
        Log-Message "Fehler in update-group-policy: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Bereinigt alte Benutzerprofile.
    
.DESCRIPTION
    Identifiziert und löscht Benutzerprofile, die seit einer bestimmten Zeit
    nicht mehr verwendet wurden.
    
.EXAMPLE
    cleanup-user-profiles
    
    Bereinigt Benutzerprofile, die seit mehr als 6000 Tagen nicht verwendet wurden.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
    Systemprofile und aktive Profile werden nicht gelöscht.
#>
function cleanup-user-profiles {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte cleanup-user-profiles"
        
        # Berechne das Datum für die Filterung (6000 Tage zurück)
        $cutoffDate = (Get-Date).AddDays(-6000)
        $cutoffFileTime = $cutoffDate.ToFileTime()
        
        Log-Message "Suche nach Benutzerprofilen, die seit $($cutoffDate.ToString('yyyy-MM-dd')) nicht verwendet wurden" "INFO"
        
        # Hole alle Benutzerprofile
        $allProfiles = Get-WmiObject -Class Win32_UserProfile -ErrorAction Stop
        
        # Filtere die zu löschenden Profile
        $profilesToDelete = $allProfiles | Where-Object {
            # Überspringe Systemprofile, spezielle Profile und das aktuell angemeldete Profil
            $_.Special -eq $false -and 
            $_.Loaded -eq $false -and 
            $_.LastUseTime -ne $null -and 
            $_.LastUseTime -lt $cutoffFileTime
        }
        
        if ($profilesToDelete.Count -eq 0) {
            Log-Message "Keine alten Benutzerprofile gefunden, die gelöscht werden können" "INFO"
            return
        }
        
        # Zeige die zu löschenden Profile an
        foreach ($profile in $profilesToDelete) {
            $lastUseDate = [DateTime]::FromFileTime($profile.LastUseTime)
            Log-Message "Wird gelöscht: $($profile.LocalPath) (Zuletzt verwendet: $($lastUseDate.ToString('yyyy-MM-dd')))" "INFO"
            
            # Lösche das Profil
            try {
                Remove-WmiObject -InputObject $profile -ErrorAction Stop
                Log-Message "Benutzerprofil gelöscht: $($profile.LocalPath)" "SUCCESS"
            } 
            catch {
                Log-Message "Fehler beim Löschen des Profils $($profile.LocalPath): $_" "ERROR"
            }
        }
        
        Log-Message "Alte Benutzerprofile erfolgreich bereinigt" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in cleanup-user-profiles: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Bereinigt temporäre Dateien.
    
.DESCRIPTION
    Löscht temporäre Dateien aus dem Windows-Temp-Verzeichnis und dem
    Temp-Verzeichnis des aktuellen Benutzers.
    
.EXAMPLE
    cleanup-temp-files
    
    Bereinigt alle temporären Dateien.
    
.NOTES
    Einige Dateien können möglicherweise nicht gelöscht werden, wenn sie 
    von Prozessen verwendet werden.
#>
function cleanup-temp-files {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte cleanup-temp-files"
        
        # Definiere zu bereinigende Verzeichnisse
        $tempFolders = @(
            @{
                Path = "C:\Windows\Temp";
                Name = "Windows-Temp";
            },
            @{
                Path = $env:TEMP;
                Name = "Benutzer-Temp";
            }
        )
        
        foreach ($folder in $tempFolders) {
            if (Test-Path -Path $folder.Path) {
                # Ermittle Größe vor der Bereinigung
                $sizeBefore = (Get-ChildItem -Path $folder.Path -Recurse -Force -ErrorAction SilentlyContinue | 
                              Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB
                
                Log-Message "$($folder.Name)-Verzeichnis Größe vor Bereinigung: $([math]::Round($sizeBefore, 2)) MB" "INFO"
                
                # Versuche, alle Dateien zu löschen
                $errorCount = 0
                Get-ChildItem -Path "$($folder.Path)\*" -Recurse -Force -ErrorAction SilentlyContinue | 
                ForEach-Object {
                    try {
                        Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
                    } 
                    catch {
                        $errorCount++
                    }
                }
                
                # Ermittle Größe nach der Bereinigung
                $sizeAfter = (Get-ChildItem -Path $folder.Path -Recurse -Force -ErrorAction SilentlyContinue | 
                              Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum / 1MB
                
                $savedSpace = $sizeBefore - $sizeAfter
                Log-Message "$($folder.Name)-Verzeichnis Größe nach Bereinigung: $([math]::Round($sizeAfter, 2)) MB (gespart: $([math]::Round($savedSpace, 2)) MB)" "SUCCESS"
                
                if ($errorCount -gt 0) {
                    Log-Message "Konnte $errorCount Dateien in $($folder.Name) nicht löschen (möglicherweise in Verwendung)" "WARNING"
                }
            }
            else {
                Log-Message "$($folder.Name)-Verzeichnis nicht gefunden" "WARNING"
            }
        }
        
        Log-Message "Temporäre Dateien erfolgreich bereinigt" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in cleanup-temp-files: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Bereinigt den DNS-Client-Cache.
    
.DESCRIPTION
    Löscht alle DNS-Einträge aus dem lokalen DNS-Client-Cache.
    
.EXAMPLE
    cleanup-dns-cache
    
    Bereinigt den DNS-Client-Cache.
#>
function cleanup-dns-cache {
    [CmdletBinding()]
    param ()
    
    try {
        Log-Message "Starte cleanup-dns-cache"
        
        # Hole DNS-Cache-Einträge vor der Bereinigung
        $entriesBefore = (Get-DnsClientCache -ErrorAction SilentlyContinue).Count
        Log-Message "DNS-Cache enthält $entriesBefore Einträge vor der Bereinigung" "INFO"
        
        # Bereinige den DNS-Cache
        Clear-DnsClientCache -ErrorAction Stop
        
        # Bestätige die Bereinigung
        $entriesAfter = (Get-DnsClientCache -ErrorAction SilentlyContinue).Count
        Log-Message "DNS-Cache erfolgreich bereinigt ($entriesBefore Einträge entfernt)" "SUCCESS"
    } 
    catch {
        Log-Message "Fehler in cleanup-dns-cache: $_" "ERROR"
    }
}

<#
.SYNOPSIS
    Hauptfunktion zur Systembereinigung.
    
.DESCRIPTION
    Führt alle definierten Bereinigungsfunktionen nacheinander aus.
    Protokolliert den Fortschritt und die Ergebnisse.
    
.EXAMPLE
    cleanup
    
    Führt eine vollständige Systembereinigung durch.
    
.NOTES
    Diese Funktion erfordert Administratorrechte.
#>
function cleanup {
    [CmdletBinding()]
    param ()
    
    try {
        $startTime = Get-Date
        Log-Message "===== STARTE SYSTEMBEREINIGUNG =====" "INFO"
        Log-Message "Startzeit: $($startTime.ToString('yyyy-MM-dd HH:mm:ss'))" "INFO"
        
        # Führe alle Bereinigungsfunktionen nacheinander aus
        Log-Message "Führe cleanup-mgr aus..." "INFO"
        cleanup-mgr
        
        Log-Message "Führe delete-folders aus..." "INFO"
        delete-folders
        
        Log-Message "Führe clear-event-logs aus..." "INFO"
        clear-event-logs
        
        Log-Message "Führe cleanup-windows-update aus..." "INFO"
        cleanup-windows-update
        
        Log-Message "Führe update-group-policy aus..." "INFO"
        update-group-policy
        
        # Benutzerprofile-Bereinigung ist standardmäßig deaktiviert (potenziell gefährlich)
        # Entfernen Sie den Kommentar, um diese Funktion zu aktivieren
        # Log-Message "Führe cleanup-user-profiles aus..." "INFO"
        # cleanup-user-profiles
        
        Log-Message "Führe cleanup-temp-files aus..." "INFO"
        cleanup-temp-files
        
        Log-Message "Führe cleanup-dns-cache aus..." "INFO"
        cleanup-dns-cache
        
        # Berechne Gesamtdauer
        $endTime = Get-Date
        $duration = $endTime - $startTime
        Log-Message "===== SYSTEMBEREINIGUNG ABGESCHLOSSEN =====" "SUCCESS"
        Log-Message "Endzeit: $($endTime.ToString('yyyy-MM-dd HH:mm:ss'))" "INFO"
        Log-Message "Gesamtdauer: $($duration.Hours) Stunden, $($duration.Minutes) Minuten, $($duration.Seconds) Sekunden" "INFO"
    } 
    catch {
        Log-Message "Kritischer Fehler in cleanup: $_" "ERROR"
    }
}

# Prüfe, ob das Skript als Administrator ausgeführt wird
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
    Write-Host "Dieses Skript erfordert Administratorrechte. Bitte starten Sie PowerShell als Administrator." -ForegroundColor Red
    exit
}

# Ausführung der Systembereinigung
cleanup

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert