Exchange Logfiles mit PowerShell bereinigen

Mitunter können die Exchange Log und Trace Files einiges an Speicherplatz belegen, ich bekomme daher immer mal wieder Anfragen, wie die Logs bereinigt werden können. In den meisten Fällen droht die Exchange Partition vollzulaufen und in vielen Fällen ist dies auch die Systempartition. Leider ist in vielen Fällen die Systempartition, auf der auch oft Exchange installiert wird, viel zu klein dimensioniert. Allein für Exchange werden 200 GB empfohlen, rechnet man noch das Betriebssystem inkl. etwas Luft (100GB) und die statische Auslagerungsdatei (32GB) dazu, kommt man schon auf gut 330 GB. Eine Systempartition mit unter 100GB ist daher auf Dauer einfach zu klein.

Exchange bereinigt übrigens die meisten seiner Logfiles selbstständig und löscht ältere Logfiles nach einer gewissen Zeit. Dies trifft aber leider nicht auf alle Logfiles und teilweise nicht erforderliche Dateien zu. So werden zum Beispiel die IIS-Logs, sowie die Dateien im Ordner „UnifiedContent“ nicht automatisch gelöscht/bereinigt.

Wenn der Speicherplatz daher mal knapp wird, kann man zunächst die Logs bereinigen um wieder etwas Luft zum Atmen zu haben. Ich habe in den meisten Fällen immer auf das Script von Ali Tajran empfohlen. In Ali’s Script müssen nur die Pfade an die eigene Umgebung angepasst werden, danach werden bei einem Durchlauf die Logfiles gelöscht.

Ali’s Script habe ich auch als Basis für das folgende Script verwendet und es etwas angepasst bzw. erweitert. Im wesentlichen wird nun auch der Ordner „UnifiedContent (\TransportRoles\data\Temp\UnifiedContent)“ bereinigt und das Script liefert eine kleine Ausgabe, wie viel Speicherplatz freigegeben wird. Zur Sicherheit gibt es auch eine kleine Abfrage ob die Daten wirklich gelöscht werden sollen.

Hier findet sich das angepasste Script:

# Cleanup logs older than the set of days in numbers
$Days = 14
# Path of the logs that you like to cleanup
$IISLogPath = "C:\inetpub\logs\LogFiles\"
$ExchangeLoggingPath = "C:\Program Files\Microsoft\Exchange Server\V15\Logging\"
$ETLLoggingPath = "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Diagnostics\ETLTraces\"
$ETLLoggingPath2 = "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Search\Ceres\Diagnostics\Logs\"
$UnifiedContentPath = "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\data\Temp\UnifiedContent"
# Test if evelated Shell
Function Confirm-Administrator {
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent() )
if ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )) {
return $true
} else {
return $false
}
}
if (-not (Confirm-Administrator)) {
Write-Output $msgNewLine
Write-Warning "This script needs to be executed in elevated mode. Start the Exchange Management Shell as an Administrator and try again."
$Error.Clear()
Start-Sleep -Seconds 2
exit
}
# Get size of all logfiles
Function Get-LogfileSize ($TargetFolder) {
if (Test-Path $TargetFolder) {
$Now = Get-Date
$LastWrite = $Now.AddDays(-$days)
$Files = Get-ChildItem $TargetFolder -Recurse | Where-Object { $_.Name -like "*.log" -or $_.Name -like "*.blg" -or $_.Name -like "*.etl" } | Where-Object { $_.lastWriteTime -le "$lastwrite" }
$SizeGB = ($Files | Measure-Object -Sum Length).Sum / 1GB
$SizeGBRounded = [math]::Round($SizeGB,2)
return $SizeGBRounded
}
Else {
Write-Output "The folder $TargetFolder doesn't exist! Check the folder path!"
}
}
Function Get-UnifiedContentfileSize ($TargetFolder) {
if (Test-Path $TargetFolder) {
$Now = Get-Date
$LastWrite = $Now.AddDays(-$days)
$Files = Get-ChildItem $TargetFolder -Recurse | Where-Object { $_.lastWriteTime -le "$lastwrite" }
$SizeGB = ($Files | Measure-Object -Sum Length).Sum / 1GB
$SizeGBRounded = [math]::Round($SizeGB,2)
return $SizeGBRounded
}
Else {
Write-Output "The folder $TargetFolder doesn't exist! Check the folder path!"
}
}
# Remove the logs
Function Remove-Logfiles ($TargetFolder) {
if (Test-Path $TargetFolder) {
$Now = Get-Date
$LastWrite = $Now.AddDays(-$days)
$Files = Get-ChildItem $TargetFolder -Recurse | Where-Object { $_.Name -like "*.log" -or $_.Name -like "*.blg" -or $_.Name -like "*.etl" } | Where-Object { $_.lastWriteTime -le "$lastwrite" }
$FileCount = $Files.Count
$Files | Remove-Item -force -ea 0
return $FileCount
}
Else {
Write-Output "The folder $TargetFolder doesn't exist! Check the folder path!"
}
}
Function Remove-UnifiedContent ($TargetFolder) {
if (Test-Path $TargetFolder) {
$Now = Get-Date
$LastWrite = $Now.AddDays(-$days)
$Files = Get-ChildItem $TargetFolder -Recurse | Where-Object { $_.lastWriteTime -le "$lastwrite" }
$FileCount = $Files.Count
$Files | Remove-Item -force -ea 0
return $FileCount
}
Else {
Write-Output "The folder $TargetFolder doesn't exist! Check the folder path!"
}
}
# Get logs and traces and write some stats
$IISLogSize = Get-LogfileSize $IISLogPath
$ExchangeLogSize = Get-LogfileSize $ExchangeLoggingPath
$ETL1LogSize = Get-LogfileSize $ETLLoggingPath
$ETL2LogSize = Get-LogfileSize $ETLLoggingPath2
$UnifiedContentSize = Get-UnifiedContentfileSize $UnifiedContentPath
$TotalLogSize = $IISLogSize + $ExchangeLogSize + $ETL1LogSize + $ETL2LogSize + $UnifiedContentSize
write-host "Total Log and Trace File Size is $TotalLogSize GB"
#Ask if script should realy delete the logs
$Confirmation = Read-Host "Delete Exchange Server log and trace files? [y/n]"
while($Confirmation -notmatch "[yYnN]") {
if ($Confirmation -match "[nN]") {exit}
$Confirmation = Read-Host "Delete Exchange Server log and trace files? [y/n]"
}
# Delete logs (if confirmed) and write some stats
if ($Confirmation  -match "[yY]") {
$DeleteIISFiles = Remove-Logfiles $IISLogPath
$DeleteExchangeLogs = Remove-Logfiles $ExchangeLoggingPath
$DeleteETL1Logs = Remove-Logfiles $ETLLoggingPath
$DeleteETL2Logs = Remove-Logfiles $ETLLoggingPath2
$DeleteUnifiedContent = Remove-UnifiedContent $UnifiedContentPath
$TotalDeletedFiles = $DeleteIISFiles + $DeleteExchangeLogs + $DeleteETL1Logs + $DeleteETL2Logs + $DeleteUnifiedContent
write-host "$TotalDeletedFiles files deleted"
}
Exchange Logfiles mit PowerShell bereinigen

Je nach Anzahl der Logs benötigt das Script etwas Zeit um die Dateien zu löschen, daher einfach etwas abwarten bis das Script durchgelaufen ist. Das Script findet sich auch auf GitHub und wird dort auch bei Bedarf aktualisiert.

6 Gedanken zu „Exchange Logfiles mit PowerShell bereinigen“

  1. Habe ich auch im Einsatz – lasse das 1x im Monat laufen.
    Ali und Frank sind TOP Männer :)

    Ali Tajran hat sie wie du Frank, einen super Blog. Hat mir schon etliche Male aus der Bredouille geholfen….

    LG

    Antworten
  2. Hi,

    in der Version auf auf GitHub gibt es die folgenden Zeilen. Wurden die vergessen auszudokumentieren?

    Gruß Hardy

    #temp for testing

    $Days = 1
    $IISLogPath = „D:\IIS-Logs“
    $ExchangeLoggingPath = „D:\Exchange Server\Logging“
    $ETLLoggingPath = „D:\Exchange Server\Bin\Search\Ceres\Diagnostics\ETLTraces“
    $ETLLoggingPath2 = „D:\Exchange Server\Bin\Search\Ceres\Diagnostics\Logs“
    $UnifiedContentPath = „D:\Exchange Server\TransportRoles\data\Temp\UnifiedContent“

    Antworten
  3. Tolles Script. Danke dafür.

    Ich würde aber den Zeitraum auf mind. 30 Tage setzen. Wenn ich an das Theater dieses Jahr mit den Exchange Hacks denke, da war es gut die Logs längere Zeit zu haben um nach Spuren zu suchen. Gerade das IIS Log.

    Antworten
  4. Bedanke mich auch für das tolle Skript. :)

    Lässt sich die Abfrage deaktivieren, bzw. direkt mit y bestätigen?
    Dann würde ich es automatisiert in der Aufgabenplanung laufen lassen.

    Antworten
  5. Ich halte das Löschen bzw. das Überschreiben der Logfiles für Kontraproduktiv. Im Falle einer Kompromittierung bietet die Auswertung der hoffentlich längerfristig als lediglich 30 Tage angelegten Logfiles die Möglichkeit, den Angriffsweg nachzuvollziehen, das Schadensausmaß zu verifizieren und die ausgenutzte Lücke zu schließen. Besser als die pauschale Löschung ist die Auslagerung und Archivierung der Logfiles.

    Antworten

Schreibe einen Kommentar