Exchange Server lassen nach nahezu jedem Update alte Daten bzw. Versionen der OWA und ECP Verzeichnisse auf dem Dateisystem liegen. Insbesondere das Verzeichnis „C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\prem“ belegt nach längerer Laufzeit und entsprechend vielen Updates doch einigen Platz auf dem Dateisystem. Hier mal ein Beispiel von einem Exchange Server der schon etwas länger läuft:
Alte Dateiversionen / Daten im Verzeichnis „prem“ belegen hier immerhin 16 GB auf dem Dateisystem. Genutzt werden diese Daten nicht mehr. Frank C. (msXfaq) hat zu diesem Thema einen lesenswerten Artikel erstellt:
https://www.msxfaq.de/exchange/update/alte_owa_dateien_loeschen.htm
Zwar dürften die „paar“ GB die wenigstens Leute aus der Ruhe bringen, aber es könnte ja mal knapp werden mit dem Speicherplatz. Wenn ein Laufwerk droht vollzulaufen, macht es also Sinn, wenn man weiß wo man sich etwas Luft zum Atmen verschaffen kann. Neben den Logfiles der Exchange Server lässt sich also auch hier etwas Speicherplatz gewinnen.
Frank C. hat in seinem Artikel auch den folgenden Satz stehen:
Das Löschen alter Versionen könnten Sie natürlich auch per PowerShell o.ä. automatisieren.
Quelle: https://www.msxfaq.de/exchange/update/alte_owa_dateien_loeschen.htm
Den Satz habe ich mal aufgenommen und in ein PowerShell Script umgewandelt. Das nachstehende PowerShell Script listet alle alten Versionsstände in den folgenden Verzeichnissen auf:
- $exinstall\ClientAccess\ecp
- $exinstall\ClientAccess\Owa
- $exinstall\ClientAccess\Owa\prem
Zur Sicherheit ermittelt das Script die älteste Exchange Server Version (in Umgebungen mit mehreren Exchange Servern) und listet alle Versionen der Verzeichnisse auf, die älter als der älteste Exchange Server sind. Somit bleibt gewährleistet, dass die Verzeichnisversionen passend zum Build des ältesten Exchange Servers vorhanden bleiben und nicht gelöscht werden.
Das Script listet beim Ausführen nur die alten Verzeichnisversionen auf, löscht diese aber nicht. Erst wenn der Parameter „-$DeleteOldVersions:$true“ angegeben wird, werden die Daten auch gelöscht.
Hier nun das Script, welches in eine .PS1 Datei kopiert werden kann:
<#
.SYNOPSIS
Identifies, reports and deletes old OWA / ECP folders
.DESCRIPTION
Run this Script to list old and unused OWA / ECP folder. Set Parameter -DeleteOldVersions to $true if you
want to delete old folders to free up disk space.
.PARAMETER DeleteOldVersions
Set DeleteOldVersions to $True to delete old OWA / ECP folder versions.
.EXAMPLE
.\Delete-OldFolderVersions.ps1
List old OWA / ECP folderversions:
.EXAMPLE
.\Delete-OldFolderVersions.ps1 -DeleteOldVersions $true
List and delete old OWA / ECP Directory versions:
.NOTES
Author: Frank Zoechling
Website: https://www.frankysweb.de
Twitter: @FrankysWeb
#>
Param(
[Parameter(Mandatory=$False)]
[bool]$DeleteOldVersions
)
# 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
}
#Foldernames to search for old ECP / OWA folders
$ECPFolderPath = $exinstall + "ClientAccess\ecp"
$OWAFolderPath = $exinstall + "ClientAccess\Owa"
$OWAPremFolderPath = $exinstall + "ClientAccess\Owa\prem"
#Get Exchange Server Versions
try {
$ExchangeServerVersions = @()
$ExchangeServerDisplayVersions = (Get-ExchangeServer | Where-Object { $_.AdminDisplayVersion.Major -eq 15 }).AdminDisplayVersion
foreach ($ExchangeServerDisplayVersion in $ExchangeServerDisplayVersions) {
$ExchangeServerVersions += $ExchangeServerDisplayVersion.Major,$ExchangeServerDisplayVersion.Minor,$ExchangeServerDisplayVersion.Build,$ExchangeServerDisplayVersion.Revision -join "."
}
$ExchangeServerVersion = $ExchangeServerVersions | Sort-Object | Select-Object -first 1
write-host ""
write-host "Oldest installed Exchange Build is: $ExchangeServerVersion"
write-host ""
} catch {}
#Search all OWA / ECP folder versions
try {
$AllVersions = @()
$AllVersions += Get-ChildItem $ECPFolderPath -Directory | Where-Object { $_.Name.StartsWith("15.") } | Select-Object FullName,Name
$AllVersions += Get-ChildItem $OWAFolderPath -Directory | Where-Object { $_.Name.StartsWith("15.") } | Select-Object FullName,Name
$AllVersions += Get-ChildItem $OWAPremFolderPath -Directory | Where-Object { $_.Name.StartsWith("15.") } | Select-Object FullName,Name
} catch {}
#Search for old versions
write-host "Old OWA / ECP folders:"
write-host ""
$ExchangeBuild = [System.Version]::Parse($exchangeserverversion)
$OldVersions = @()
foreach ($Version in $AllVersions) {
$Folderversion = [System.Version]::Parse($Version.Name)
if ( $Folderversion -lt $ExchangeBuild ) {
write-host $Version.Fullname
$OldVersions += $Version.Fullname
}
}
write-host ""
#Delete old OWA / ECP folder versions
if ($DeleteOldVersions -eq $true) {
write-host "Deleting old OWA / ECP versions:"
write-host ""
foreach ($Oldversion in $OldVersions) {
write-host $Oldversion
Remove-Item $Oldversion -Recurse -Confirm:$true
}
}
Wer es etwas einfacher haben möchte, das Script habe ich auch auf GitHub veröffentlicht:
Update 07.12.2021: Das Script wurde aktualisiert damit mehr ältere Versionen erfasst werden, die Änderungen lassen sich auf GitHub nachvollziehen. Vielen Dank für den Pull Request.
Hallo Frank, ich habe das Skript in der Vergangenheit erfolgreich genutzt. Nach Update auf Build 1544.4.11 funktioniert die Ermittlung der installierten Exchange Versionen nicht mehr.
(Get-ExchangeServer).AdminDisplayVersion liefert „Version 15.2 (Build 1544.4)“. Die Felder „Major“ usw. gibt es scheinbar nicht mehr.
Daher liefert die folgende Zeile im Skript keinen Wert:
$ExchangeServerDisplayVersions = (Get-ExchangeServer | Where-Object { $_.AdminDisplayVersion.Major -eq 15 }).AdminDisplayVersion
In der Folge kommt dann dieser Fehler in Zeile 76:
Ausnahme beim Aufrufen von „Parse“ mit 1 Argument(en): „Der Wert darf nicht NULL sein.
Parametername: input“
In D:\Delete-OldFolderVersions.ps1:76 Zeichen:1
+ $ExchangeBuild = [System.Version]::Parse($exchangeserverversion)
i created a new script which work with the latest exchange version. you can download it here
https://github.com/Florgo88/Clean-Old-ECP-and-OWA-Versions/blob/main/CleanOldECPAndOWA.ps1
Hallo Frank,
heute, zwei Jahre nachdem du diesen Beitrag geschrieben hast, hilfst du immer noch Menschen, die im Internet nach Lösungen für Exchange-Probleme suchen, und bietest hier eine Heimat für Wissen.
Ich möchte dir hiermit nur meinen Dank aussprechen und dir weiterhin viel Erfolg in deiner Karriere wünschen.
Alles Gute,
L. Correia
Letzte Version des Scripts von GitHub geladen und elevated ausgeführt.
Folgende Ausgabe:
###############
Oldest installed Exchange Build is: 15.2.1118.7
Old OWA / ECP folders:
###############
Also unterhalb von „Old OWA / ECP folders:“ steht einfach mal gar nichts.
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa beherbergt aber durchaus 8,04 GB und hat u.a. die Unterordner
15.2.1118.7 15.2.1118.12 15.2.1118.26
Wer macht da was falsch: Ich? Das Skript? Mein eventueller Vorgänger der auf der an Platz knappen Maschine gg.f schon etwas per Hand herausoperiert hat???
Super Skript.
Da ich bei mir privat nur einen einzigen Domain Controller sowie nur einen einzigen Exchange Server habe (auf der selben Maschine),
kann ich im grundsätzlich problemlos ALLE alten Versionen löschen.
Es gibt für mich in aller Regel Null Gründe, zu einer alten Version zurückzukehren.
WENN Fehler auftreten, habe ich eben eine kurze Downzeit, tut mir als Privatperson aber nicht SO sehr weh,
da Strato als Backup-MX fungiert und die Mails vorläufig entgegennehmen würde.
Danke für das feine Script! Das hilft wirtschaften.
Bei meinen Tests hat es aber bei jedem Verzeichnis trotz „A“ Auswahl immer wieder nachgefragt:
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\15.1.845.34“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“): A
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\15.1.845.36
Bestätigung
Möchten Sie diese Aktion wirklich ausführen?
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\15.1.845.36“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“): A
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\prem\15.1.1466.3
Bestätigung
Möchten Sie diese Aktion wirklich ausführen?
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\prem\15.1.1466.3“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“): A
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\prem\15.1.1713.1
Bestätigung
Möchten Sie diese Aktion wirklich ausführen?
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\prem\15.1.1713.1“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“): A
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\prem\15.1.1779.2
Bestätigung
Möchten Sie diese Aktion wirklich ausführen?
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\prem\15.1.1779.2“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“): A
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\Owa\prem\15.1.1779.3
Bestätigung
Möchten Sie diese Aktion wirklich ausführen?
Ausführen des Vorgangs „Verzeichnis entfernen“ für das Ziel „C:\Program Files\Microsoft\Exchange
Server\V15\ClientAccess\Owa\prem\15.1.1779.3“.
[J] Ja [A] Ja, alle [N] Nein [K] Nein, keine [H] Anhalten [?] Hilfe (Standard ist „J“):
Mache ich da was falsch?
Du liest die Kommentare nicht. Simon hat das oben erklärt. ;)
Danke für dein Script, ich warte schon lange auf eine Lösung für dieses Kumulieren von alten Dateien. Inzwischen sind das bei mir >40GB, die in jedes Backup (inkl. Aufbewahrung mehrerer Zeitpunkte) eingehen, das läppert sich und kostet Backupspeicher und Backupzeit.
Aktuell lasse ich das Script noch etwas „reifen“ und habe das Delete noch nicht aktiv ausführen lassen.
Bei der Prüfung fällt mir aber schon folgendes auf (ich habe 1x Exchange 2016 mit letztem CU und Updates):
>>Oldest installed Exchange Build is: 15.1.2375.7
Ich finde aber Ordner mit 15.1.2375.12 und 15.1.2375.17.
Grund ist wohl der schlampige Umgang von MS mit Versionsinfos. Im Exchange Admin Center wird mir auch nur build 2375.7 angezeigt, die ExSetup.exe hat aber in ihren Eigenschaften das neueste build 2375.17 (siehe https://community.spiceworks.com/topic/2337762-unable-to-update-to-exchange-2016-15-1-2375-12)
Grund ist, dass im AD die Version nicht exakt mitgepflegt wird.
Beim Einsatz des Scriptes werden also aus diesem Grund immer ein paar Ordner nicht gelöscht werden, obwohl der Exchange schon neueren Datums ist. Aber das ist verschmerzbar, wenn es nicht sogar noch Vorteile in manchen Umgebungen hat.
In Zeile 82 vom Script musste ich eine Anpassung mache, da sonst ich ständig mit „Y“ oder „A“ bestätigen muss zum löschen.
Anstatt „Remove-Item $Oldversion -Recurse -Confirm:$true“ zu nehmen habe ich „Remove-Item $Oldversion -Recurse -ErrorAction SilentlyContinue“ verwendet. Damit löscht es die Ordner ohne zu fragen. Ich verwende Exchange 2013 mit Server 2012 R2.
Gruß
Simon
Etwas eleganter:
Remove-Item $Oldversion -Recurse -Confirm:$false
Ist das eigentlich ein Bug oder eine Feature das diese Leichen über bleiben? Ich find es eine Schande das Microsoft das nicht in Griff bekommt.
Danke Franky für das script, mein innerer Monk ist damit befriedigt!
Das ist kein Bug und auch kein Feature sondern unter Umständen notwendig wenn da mehrere Server vernetzt sind. Im MSXfaq Artikel ist beschrieben warum manchmal die alte Version gebraucht wird.
Hi,
ja, wieder ein prima Script, merci vielmals !
Ich frage mich nur, was Du mit „Oldest“ meinst ? Für mich ist das der „latest“, also der Ordner der beim letzten Update entstanden ist.
Ich habe auch festgestellt, daß mir als Oldest installed Exchange Build is: 15.1.2308.8 angezeigt wird, aber es die 15.1.2308.20 gibt.
Zwischen den beiden liegt noch die .14.
Gibt es da ne Erklärung ?
Tx,
Gruß
Volker
Es wird unter allen bei dir in der Org installierten Exchangeservern die „älteste“ angezeigt.
Name : EX16
Edition : Standard
AdminDisplayVersion : Version 15.1 (Build 2308.8)
Name : EX19
Edition : Standard
AdminDisplayVersion : Version 15.2 (Build 986.5)
Ergibt im Skript dann:
Oldest installed Exchange Build is: 15.1.2308.8
Hallo Norbert,
ich habe 3 EXCH2016. Wenn ich die abfrage erhalte ich
Enterprise Version 15.1 (Build 2308.8)
Enterprise Version 15.1 (Build 2308.8)
Enterprise Version 15.1 (Build 2308.8)
Also alle auf gleichem Build und für mich das „jüngste“ und nicht das älteste.
Welchen Standpunkt soll ich einnehmen, damit ich das verstehe ;) ?
Ganz einfach. Die latest ist vollkommen egal, weil du ja die „älteste“ berücksichtigen musst. Also aktualisier beim nächsten mal nur einen oder zwei deiner Server und schon wird’s klar.
Hallo,
vielen Dank für das Script. Soweit funktioniert es bei uns. Jedoch haben ich zwei Phänomene.
1. Laut Script ist unsere Exchange-Version 15.2.986.5, in Verzeichnissen liegen aber bereits Ordner für .9 und .14 ab, selbe Ordnergröße wie .5, welches ist nun die wahre „latest Version“?
2. Es bleiben nach dem Durchlauf trotzdem noch diverse Verzeichnisse übrig, z. B. 15.2.858.10, das Script mehrmals durchlaufen bringt nix, diese Verzeichnisse werden nicht erkannt.
Beide oben aufgeführten Phänomene treten bei beiden Exchange 2019 Servern auf.
Eine Idee?
Ich denke das liegt daran, wie das Script die Versionsnummern vergleicht. Auf GitHub hat hier auch schon jemand einen Verbesserungsvorschlag eingereicht:
https://github.com/FrankysWeb/Delete-Old-OWA-and-ECP-Versions/pull/1
Das ist wahrscheinlich nur eine Frage der Zeit, bis das von Frank übernommen wird.
VG
Martin
Vielen Dank!
Hier verbleiben aber noch Versionen: 15.1.1847.10 / 15.1.2176.12 / 15.1.2176.14 / 15.1.2308.14
Ist das gewollt so?
Grüsse Stefan
Oha, das ist ja mega! Bei der letzten Reinigung hab ich das noch manuell gemacht. Vielen Dank für Mühe und so ein tolles Script
Ich bekomme folgende Fehlermeldung in der Exchange Shell:
[PS] C:\scripte>.\Delete-OldFolderVersions.ps1 -$DeleteOldVersions:$true
In Zeile:1 Zeichen:33
+ .\Delete-OldFolderVersions.ps1 -$DeleteOldVersions:$true
+ ~~~~~~~~~~~~~~~~~~~
Ungültiger Variablenverweis. Nach „:“ folgte kein Zeichen, das für einen Variablennamen gültig ist. Verwenden Sie ggf.
„${}“, um den Namen zu begrenzen.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : InvalidVariableReferenceWithDrive
Bei -$DeleteOldVersions muss das $ entfernt werden. Also -DeleteOldVersions.
Versuch mal „.\Delete-OldFolderVersions.ps1 -DeleteOldVersions $true“ wie Frank in seinen Comments im Script auch geschrieben hat :)
OMG! Das ist ja mal maximal peinlich!
Vielen Dank fürs Wecken und Erleuchten!
Viele Grüße
Marcus
Nahmd Frank,
wieder einmal ein prima Artikel von dir!
Leider scheine ich ein wenig zu dusslig zu sein, denn ebim Ausführen des Scripts bekomme ich Fehler:
PS D:\Scripts> .\Delete-OldFolderVersions.ps1
Get-ChildItem : Der Pfad „D:\Scripts\ClientAccess\ecp“ kann nicht gefunden werden, da er nicht vorhanden ist.
In D:\Scripts\Delete-OldFolderVersions.ps1:66 Zeichen:21
+ $AllVersions += Get-ChildItem $ECPFolderPath -Directory | Where-O …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\Scripts\ClientAccess\ecp:String) [Get-ChildItem], ItemNotFoundExcept
ion
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Get-ChildItem : Der Pfad „D:\Scripts\ClientAccess\Owa“ kann nicht gefunden werden, da er nicht vorhanden ist.
In D:\Scripts\Delete-OldFolderVersions.ps1:67 Zeichen:21
+ $AllVersions += Get-ChildItem $OWAFolderPath -Directory | Where-O …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\Scripts\ClientAccess\Owa:String) [Get-ChildItem], ItemNotFoundExcept
ion
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Get-ChildItem : Der Pfad „D:\Scripts\ClientAccess\Owa\prem“ kann nicht gefunden werden, da er nicht vorhanden ist.
In D:\Scripts\Delete-OldFolderVersions.ps1:68 Zeichen:21
+ … $AllVersions += Get-ChildItem $OWAPremFolderPath -Directory | Where …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\Scripts\ClientAccess\Owa\prem:String) [Get-ChildItem], ItemNotFoundE
xception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Old OWA / ECP folders:
Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
In D:\Scripts\Delete-OldFolderVersions.ps1:74 Zeichen:1
+ [int]$ExchangeBuild = $ExchangeServerVersion.Replace(„.“,““)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Irgendwie findet der Script den Ordner D:\Exchange nicht.
Vielen Dank und viele Grüße
Marcus
Hallo Marcus,
du musst das Script mit der Exchange Shell ausführen.
Gruß,
Frank