WSUS Server aufräumen und bereinigen

Die Windows Server Update Services, kurz WSUS, sollte man von Zeit zu Zeit warten und nicht benötigte Updates entfernen. Das geht zum einen recht gut mit dem “Assistent für die Serverbereinigung”, jedoch muss man auch Hand anlegen und sollte zum Beispiel die Updates entfernen die von anderen ersetzt wurden (Superseded Updates). Und das erkläre ich nachfolgend.

WSUS aufräumen von Superseded Updates oder in deutsch die von anderen Updates ersetzt wurden

Die Frage vorweg – Warum sollte man das machen? Der Grund ist recht einfach um den Speicher auf der Festplatte des WSUS möglichst schlank zu halten und um ggf. Fehler wie “WARNING: Exceeded max server round trips: 0x80244010” auf dem Windowsclient  zu vermeiden.

  1. WSUS Konsole starten
  2. in die Ansicht Updates -> Alle Updates wechseln
    WSUS Ansicht Alle Updates
    WSUS Ansicht Alle Updates
  3. den Filter wie folgt einstellen:
    WSUS Filter Settings
    WSUS Filter Settings

     

     

    1. Genehmigung: “Alle bis auf abgelehnte”
    2. Status: “Any”
    3. und auf “Aktualisieren” klicken
  4. nun ggf. noch die Spalte “Ersatz” aktivieren
    WSUS Spalte Ersatz
    WSUS Spalte Ersatz
  5. alle Updates nach der Spalte “Ersatz” sortieren

WSUS Symbole Ersatz

Da sich nun alles um die Superseded Updates dreht, erkläre ich nachfolgend kurz die Symbole:

Symbol Erklärung Ablehnen / Löschen
WSUS Symbol kein Ersatz
WSUS Symbol kein Ersatz
Dieses Update ersetzt andere Updates nein !
WSUS Symbol Wird und ist Ersatz
WSUS Symbol Wird und ist Ersatz
Dieses Update ersetzt ein Update, wird aber auch von einem anderen ersetzt. Ja
WSUS Symbol Ersatz
WSUS Symbol Ersatz
Dieses Update wird von einem anderen Update ersetzt. Ja
  • Weiter geht es an dieser Stelle und wir prüfen ob die Updates, die die andere Ersetzen, auch genehmigt wurden und zur Installation freigegeben sind. Dafür schaue ich unter “Zusätzliche Details” nach dem Punkt “Updates, die dieses Update ersetzen:” Dort klicke ich auf das entsprechende Update das dieses ersetzt und schaue mir von diesem Update die “Genehmigungszusammenfassung” an. Dieses sollte also zur Installation genehmigt werden.
  • ist dies der Fall können alle Updates die Ersetzt wurden ablehnen
    WSUS Ersatz Ablehnen
    WSUS Ersatz Ablehnen
  • im letzten Schritt wird der “Assistent für die Serverbereinigung” ausgeführt
    • unter “Optionen” -> auf “Assistent für die Serverbereinigung” klicken
      WSUS Option Assitent Bereinigung
      WSUS Option Assitent Bereinigung
  • hier nun entsprechend den eigenen Vorgaben, die entsprechenden Optionen auswählen, ich nehme alle, Beschreibung sollte selbsterklärend sein
    WSUS Server Bereinigung Optionen
    WSUS Server Bereinigung Optionen
  • und den Assistenten starten

Das Resultat

Damit wurden alle nicht mehr benötigten Windows Updates von der Festplatte gelöscht und Platz geschaffen. Auch wurden alle von Computern für diese Updates gemeldeten Ereignisse aus der Datenbank gelöscht. Dadurch müssen Clients ggf. nicht zu viele Anfragen zur Klärung des Updatestatus an den Server senden und Probleme wie den Roun Trip, werden vermieden. Wird nun ein neuer Client installiert, so wird er immer das neueste Update installieren, es hat ja eh ein altes und nun entferntes ersetzt …

Empfehlung – Automatische Genehmigung

Unter Optionen -> “Automatische Genehmigungen” und dort unter dem Reiter “Erweitert” empfehle ich die Optionen für die “Revisionen für Updates” zu aktivieren:

  • Neue Revisionen von bereits genehmigten Updates automatisch genehmigen
    • Updates automatisch ablehnen, wenn eine neue Revision deren Ablauf bewirkt
WSUS Option Auto Genehmigung
WSUS Option Auto Genehmigung

Aufräumen mittels Powershell

Der WSUS lässt sich auch per Powershell verwalten. So kann man mittels einfachem Befehl obiges einfach per Powershell ausführen und z.B. automatisiert in regelmäßigen Abständen durchführen. Nachfolgender Powershellbefehl führt folgendes durch:

  • entfernen aller Superseeded Updates
  • entfernen aller Expired Updates
  • entfernen alte Computer

und los gehts:

  • auf dem WSUS anmelden
  • Powershell als Administrator öffnen und folgenden Befehl eingeben und ausführen:
Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteComputers -CleanupObsoleteUpdates

Diesen Befehl muss man ggf. öfter hintereinander ausführen, da ansonten ein Fehler mit “..Timeout..” erfolgt, der Befehl dann aber an der Stelle wo es aufhörte, weiter macht. In meinem Fall hatte ich nach 9 maligem ausführen die Nase voll und habe diese einfache Powershell While-Schleife laufen lassen. Diese lief dann über Nacht und wurde ca. 320x ausgeführt :uff: Danach wurde mir der Erfolg angezeigt und der WSUS aufgeräumt.

#$wsus = Get-WsusServer -Name localhost -port 8530 #Extra
#$wsus.GetDatabaseConfiguration().CreateConnection() # Extra
while(!($Check))
{
    $check = $true
    try{        
        Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteComputers -CleanupObsoleteUpdates        
    }
    catch{
        $check = $false
        Write-Host "Timeout"
    }
}

WSUS Datenbank reorganisieren

  • Windows Server 2016 mit WSUS in lokaler SQLExpress Datenbank

Von Zeit zu Zeit ist es notwendig die WSUS Datenbank zu reorganisieren und damit die Indexes neuzuerstellen und fragementierte Tabellen aufzuräumen. Hierfür gibt es ein sehr gutes SQL-Script in der Microsoft Technet Gallery: https://gallery.technet.microsoft.com/scriptcenter/Optimize-and-cleanup-of-eb9d8640 das den Job übernimmt. Man kann es sehr gut z.B. monatlich als Task laufen lassen.

Voraussetzung ist die Installation der Tools für SQLCMD, steht aber auch im Artikel.

Das Script ist für Windows Server 2012 R2 und 2016 und sieht wie folgt aktuell aus, wobei ich den Schalter “SET QUOTED_IDENTIFIER ON;” bereits hinzugefügt habe:

/****************************************************************************** 
This sample T-SQL script performs basic maintenance tasks on SUSDB 
1. Identifies indexes that are fragmented and defragments them. For certain 
   tables, a fill-factor is set in order to improve insert performance. 
   Based on MSDN sample at http://msdn2.microsoft.com/en-us/library/ms188917.aspx 
   and tailored for SUSDB requirements 
2. Updates potentially out-of-date table statistics. 
******************************************************************************/ 
 
USE SUSDB; 
GO 
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON; 
 
-- Rebuild or reorganize indexes based on their fragmentation levels 
DECLARE @work_to_do TABLE ( 
    objectid int 
    , indexid int 
    , pagedensity float 
    , fragmentation float 
    , numrows int 
) 
 
DECLARE @objectid int; 
DECLARE @indexid int; 
DECLARE @schemaname nvarchar(130);  
DECLARE @objectname nvarchar(130);  
DECLARE @indexname nvarchar(130);  
DECLARE @numrows int 
DECLARE @density float; 
DECLARE @fragmentation float; 
DECLARE @command nvarchar(4000);  
DECLARE @fillfactorset bit 
DECLARE @numpages int 
 
-- Select indexes that need to be defragmented based on the following 
-- * Page density is low 
-- * External fragmentation is high in relation to index size 
PRINT 'Estimating fragmentation: Begin. ' + convert(nvarchar, getdate(), 121)  
INSERT @work_to_do 
SELECT 
    f.object_id 
    , index_id 
    , avg_page_space_used_in_percent 
    , avg_fragmentation_in_percent 
    , record_count 
FROM  
    sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'SAMPLED') AS f 
WHERE 
    (f.avg_page_space_used_in_percent < 85.0 and f.avg_page_space_used_in_percent/100.0 * page_count < page_count - 1) 
    or (f.page_count > 50 and f.avg_fragmentation_in_percent > 15.0) 
    or (f.page_count > 10 and f.avg_fragmentation_in_percent > 80.0) 
 
PRINT 'Number of indexes to rebuild: ' + cast(@@ROWCOUNT as nvarchar(20)) 
 
PRINT 'Estimating fragmentation: End. ' + convert(nvarchar, getdate(), 121) 
 
SELECT @numpages = sum(ps.used_page_count) 
FROM 
    @work_to_do AS fi 
    INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id 
    INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id 
 
-- Declare the cursor for the list of indexes to be processed. 
DECLARE curIndexes CURSOR FOR SELECT * FROM @work_to_do 
 
-- Open the cursor. 
OPEN curIndexes 
 
-- Loop through the indexes 
WHILE (1=1) 
BEGIN 
    FETCH NEXT FROM curIndexes 
    INTO @objectid, @indexid, @density, @fragmentation, @numrows; 
    IF @@FETCH_STATUS < 0 BREAK; 
 
    SELECT  
        @objectname = QUOTENAME(o.name) 
        , @schemaname = QUOTENAME(s.name) 
    FROM  
        sys.objects AS o 
        INNER JOIN sys.schemas as s ON s.schema_id = o.schema_id 
    WHERE  
        o.object_id = @objectid; 
 
    SELECT  
        @indexname = QUOTENAME(name) 
        , @fillfactorset = CASE fill_factor WHEN 0 THEN 0 ELSE 1 END 
    FROM  
        sys.indexes 
    WHERE 
        object_id = @objectid AND index_id = @indexid; 
 
    IF ((@density BETWEEN 75.0 AND 85.0) AND @fillfactorset = 1) OR (@fragmentation < 30.0) 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE'; 
    ELSE IF @numrows >= 5000 AND @fillfactorset = 0 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD WITH (FILLFACTOR = 90)'; 
    ELSE 
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD'; 
    PRINT convert(nvarchar, getdate(), 121) + N' Executing: ' + @command; 
    EXEC (@command); 
    PRINT convert(nvarchar, getdate(), 121) + N' Done.'; 
END 
 
-- Close and deallocate the cursor. 
CLOSE curIndexes; 
DEALLOCATE curIndexes; 
 
 
IF EXISTS (SELECT * FROM @work_to_do) 
BEGIN 
    PRINT 'Estimated number of pages in fragmented indexes: ' + cast(@numpages as nvarchar(20)) 
    SELECT @numpages = @numpages - sum(ps.used_page_count) 
    FROM 
        @work_to_do AS fi 
        INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id 
        INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id 
 
    PRINT 'Estimated number of pages freed: ' + cast(@numpages as nvarchar(20)) 
END 
GO 
 
 
--Update all statistics 
PRINT 'Updating all statistics.' + convert(nvarchar, getdate(), 121)  
EXEC sp_updatestats 
PRINT 'Done updating statistics.' + convert(nvarchar, getdate(), 121)  
GO 

Das Script wird in eine Datei gespeichert z.B. “WsusDBMaintenance.sql”, die dann später im Task aufgerufen wird. Der SQLExpress läuft unter dem “NT Service” und ohne weitere Berechtigungen, sodass ich ihn auch nicht als Administrator in der Befehlszeile ausführen konnte. Daher ein Task mit Output in ein Debug File.

WSUS Service SQL Logon User
WSUS Service SQL Logon User

Ich musste den SQLCMD Befehl aus dem obigen Artikel etwas anpassen, da er ansonsten nicht lief. Die wesentlichen Einstellungen des WSUS-Tasks:

Das Programm / Script das ausgeführt wird: # sqlcmd -S np:\.\pipe\MSSQL$SQLEXPRESS\sql\query -i <Pfad zum WsusDBMaintenance .sql Script> -o “<Pfad zur debug.txt>”

WSUS Task Cleanup Script
WSUS Task Cleanup Script

Den Task dann noch den eigenen Abläufen entsprechend anpassen und gut ist.

WSUS Datenbank verkleinern

Ein weiterer Schritt den WSUS aufzuräumen und zu optimieren ist die Datenbank zu verkleinern / shrinken. Das geht am besten mit dem MS SQL Management Studio.

WSUS SUSDB Shrink
WSUS SUSDB Shrink

Have Fun …

Loading...

21 Gedanken zu „WSUS Server aufräumen und bereinigen“

  1. Hi dein Artikel hat mir sehr weitergeholfen die “Logik” vom WSUS nachzuvollziehen und die nicht vollumfängliche Bereinigung nachvollziehen zu können. Danke dafür!
    Darauf aufbauend und mit ein bisschen Netzrecherche hier und ein bisschen CopyPaste da und ein bisschen Anpassung meinerseits habe ich folgendes powershellscript erstellt/modifiziert welches alle genehmigten WSUS Updates einliest dann deren “Ersetzt” Status prüft und daraufhin alle ersetzten Updates ablehnt. Danach wird die Autobereinigung vom WSUS aufgerufen (nur für die Updates). Somit werden sie auch gleich entfernt.
    Das ganze wird unter den eingegebenen Pfaden dann fortlaufend protokolliert (Müssen angepasst werden!).
    Quelle vom Grundscript: https://gallery.technet.microsoft.com/scriptcenter/Cleanup-WSUS-server-4424c9d6

    Wenn man dieses Script wie folgt koppelt muss man sich fast nicht mehr um den WSUS-Updatezyklus kümmern.
    1. Updatekatalogsynch zwischen WSUS und Windows Update in der Nacht
    2. Automatische Genehmigungsregeln für Updates im WSUS einstellen
    (hier geht bestimmt auch noch was mit Powershell wenn mans ganz feingliedrig haben möchte z.Bsp.: gewisse Office Produkte/Bestandteile nicht zu genehmigen)
    3. Das PowershellScript dann paar Stunden später automatisiert laufen lassen

    PS: ! $server, $port und die Logpaths müssen angepasst werden !

    Powershellcode:

    Start-Transcript -Path “C:\WSUS_Skript_Bereinigung\Log\2LogPowershell.txt” -Append

    $server = ”
    $port = ”
    Write-Progress -Activity ‘Getting WSUS server’
    $WSUSserver = Get-WsusServer -Name $server -PortNumber $port
    Write-Progress -Activity ‘Getting approved updates, this may take a while…’ -PercentComplete -1
    $approvedupdates = Get-WsusUpdate -UpdateServer $WSUSserver -Approval Approved -Status InstalledOrNotApplicableOrNoStatus
    Write-Progress -Activity ‘Retrieved updates’ -PercentComplete 90
    $i = 0
    $superseded = $approvedupdates | ? {$_.Update.IsSuperseded -eq $true}
    $total = $superseded.count

    $datum = Get-Date -Format g
    foreach ($update in $superseded)
    {
    $datum + ” [Abgelehnt] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
    }

    foreach ($update in $superseded)
    {
    Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$total) * 100)
    $update.Update.Decline()
    $i++
    }

    Write-Host “Total declined updates: $total” -ForegroundColor Yellow

    Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteUpdates -cleanupUnneededContentfiles -CompressUpdates

    Zusätzlich kann man auch die Synchberichte 1mal im Monat leeren lassen da die irgendwann ewig brauchen zum laden und zwar wie folgt:
    .sql Datei mit folgendem Inhalt erstellen lautet hier “Synchronisierungsberichteloeschen.sql” :
    USE SUSDB
    GO
    DELETE FROM tbEventInstance WHERE EventNamespaceID = ‘2’ AND EVENTID IN (‘381’, ‘382’, ‘384’, ‘386’, ‘387’, ‘389’)

    Dazu dann eine batch zum automatisieren:
    sqlcmd -S np:\\.\pipe\MICROSOFT##WID\tsql\query -i C:\WSUS_Skript_Bereinigung\Synchronisierungsberichteloeschen.sql

    Grüße

    Antworten
    • Hi,
      super das ich helfen konnte. Deine Weiterentwicklung sieht aber auch klasse aus. Leider kann ich sei grade nicht testen, aber sie hilft bestimmt den nächste …Thx

      Antworten
      • Danke.
        Mir ist heut beim testen aufgefallen das ich noch folgendes in der letzten Zeile vom 1. Script vergessen habe und somit die nicht verwendeten Updaterevisionen auf dem WSUS liegen bleiben.
        Oben:
        Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteUpdates
        Neu:
        Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteUpdates -cleanupUnneededContentfiles -CompressUpdates

        Zusätzlich habe ich noch folgendes Script gefunden welches man davor laufen lassen kann um spezielle Updates rauszukehren.
        https://gallery.technet.microsoft.com/Decline-WSUS-Update-Types-13fec5e0#content

        Antworten
          • Vielen Dank und nun kommt noch mehr 😉
            Nachdem das Script vom Technet nicht so wollte wie ich, habe ich es in das bestehende Script eingebaut.
            Für alle Produkte die man im speziellen ablehnen möchte (Sharepoint, Office 32bit Updates etc.pp.) gibt es nun einzelne Abfrageblöcke die dies erledigt.
            Somit kann man sich nach belieben eigene Regeln bauen, da in der Updatebezeichnung gesucht wird.

            Ein Block zusammengeschrieben sieht so aus wenn ich alle Itanium Updates ablehnen möchte:
            $i = 0
            $itanium = $approvedupdates | ? {$_.Update.Title -match “ia64|itanium”}
            $totalitanium = $itanium.count
            $datum = Get-Date -Format g #Wird nur einmal benötigt
            foreach ($update in $itanium)
            {
            $datum + ” [Abgelehnt] ” + ” [itanium] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $itanium)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalitanium) * 100)
            $update.Update.Decline()
            $i++
            }
            Write-Host “Total declined itanium updates: $totalitanium” -ForegroundColor Yellow

            Produkte welche man nicht ablehnen möchte muss man einfach mit “” auskommentieren im Script (ich habe das als Beispiel für die Office 32 und 64 bit Updates getan).

            Der folgende Block ersetzt im Eingangsscript alles ab der Zeile 11 also nach:
            Write-Progress -Activity ‘Retrieved updates’ -PercentComplete 90

            Script:

            $i = 0
            $superseded = $approvedupdates | ? {$_.Update.IsSuperseded -eq $true}
            $itanium = $approvedupdates | ? {$_.Update.Title -match “ia64|itanium”}
            $Sharepoint = $approvedupdates | ? {$_.Update.Title -match “SharePoint Enterprise Server|SharePoint Foundation|SharePoint Server|FAST Search Server”}
            $Win10x86 = $approvedupdates | ? {$_.Update.Title -match “Windows 10” -and $_.Update.Title -match “x86”}
            $Win10arm64 = $approvedupdates | ? {$_.Update.Title -match “Windows 10” -and $_.Update.Title -match “arm64”}
            $Officex86 = $approvedupdates | ? {$_.Update.Title -match “Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word” -and $_.Update.Title -match “32-Bit”}
            $Officex64 = $approvedupdates | ? {$_.Update.Title -match “Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word” -and $_.Update.Title -match “64-Bit”}

            $totalsuperseded = $superseded.count
            $totalitanium = $itanium.count
            $totalSharepoint = $Sharepoint.count
            $totalWin10x86 = $Win10x86.count
            $totalWin10arm64 = $Win10arm64.count
            $totalOfficex86 = $Officex86.count
            $totalOfficex64 = $Officex64.count

            $datum = Get-Date -Format g

            foreach ($update in $superseded)
            {
            $datum + ” [Abgelehnt] ” + ” [Superseded] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $superseded)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalsuperseded) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $itanium)
            {
            $datum + ” [Abgelehnt] ” + ” [itanium] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $itanium)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalitanium) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Sharepoint)
            {
            $datum + ” [Abgelehnt] ” + ” [Sharepoint] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Sharepoint)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalSharepoint) * 100)
            $update.Update.Decline()
            $i++
            }
            $i = 0

            foreach ($update in $Win10x86)
            {
            $datum + ” [Abgelehnt] ” + ” [Win10x86] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Win10x86)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalWin10x86) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Win10arm64)
            {
            $datum + ” [Abgelehnt] ” + ” [Win10arm64] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Win10arm64)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalWin10arm64) * 100)
            $update.Update.Decline()
            $i++
            }

            Write-Host “Total declined superseeded updates: $totalsuperseded” -ForegroundColor Yellow
            Write-Host “Total declined itanium updates: $totalitanium” -ForegroundColor Yellow
            Write-Host “Total declined sharepoint updates: $totalSharepoint” -ForegroundColor Yellow
            Write-Host “Total declined Windows 10 32bit updates: $totalWin10x86” -ForegroundColor Yellow
            Write-Host “Total declined Windows 10 arm64 updates: $totalWin10arm64” -ForegroundColor Yellow
            Write-Host “Total declined Office 32bit updates: $totalOfficex86” -ForegroundColor Yellow
            Write-Host “Total declined Office 64bit updates: $totalOfficex64” -ForegroundColor Yellow

            Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates

            Grüße =)

          • Irgendwie hat er in dem Posting im Skript die Auskommentierung tatsächlich auskommentiert und verschwinden lassen 😀

            Der auskommentierte Officeblock mit ist komplett weg. 🙂

          • Hier nun nochmal das komplette Skript ohne Auskommentierung (unten).
            Erklärung:
            Damit sollte es dann auch Final sein. Wie schon weiter oben beschrieben kann man sich dann auch noch eigene Filter zum ablehnen bauen welche auf den Namen des Updates zielen.
            Aktuell werden im Script ablehent:
            Alle ersetzten Updates
            itanium Updates
            Sharepoint Updates
            Windows 10 32bit
            Windows 10 ARM64
            Office 32bit
            Office 64bit

            ! Hier müssen die nicht gewünschten Schleifen einfach auskommentiert werden. !
            Zum Beispiel. man hat nur Office 64bit Installationen und möchte folglich diese Update behalten aber nicht die 32bit dann kommentiert man folgende 3 Zeilen/Blöcke aus:
            1.
            $Officex64 = $approvedupdates | ? {$_.Update.Title -match “Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word” -and $_.Update.Title -match “64-Bit”}
            2.
            $i = 0

            foreach ($update in $Officex64)
            {
            $datum + ” [Abgelehnt] ” + ” [Officex64] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Officex64)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalOfficex64) * 100)
            $update.Update.Decline()
            $i++
            }
            3.
            Write-Host “Total declined Office 64bit updates: $totalOfficex64” -ForegroundColor Yellow

            Der “Start-Transcript -Path” und “Out-File”-Paths in jeder Logschleife (hier war ich zu faul für ne Variable, CopyPaste ging schneller 😉 ) können individualisiert werden und der WSUS Servername ($server) muss geändert werden.
            Portnummer ($port) sollte eigentlich bei den meisten passen (Standardport).

            Viel Spaß damit und bleibt gesund. =)
            PS: Verbesserungsvorschläge und Fragen sind gern gelesen 😉

            ………………………………………………………………………………………………………………………………………
            Skript
            ………………………………………………………………………………………………………………………………………
            Start-Transcript -Path “C:\WSUS_Skript_Bereinigung\Log\2LogPowershell.txt” -Append

            $server = ‘[WSUSName].[Domain]’
            $port = ‘8530’

            Write-Progress -Activity ‘Getting WSUS server’
            $WSUSserver = Get-WsusServer -Name $server -PortNumber $port
            Write-Progress -Activity ‘Getting approved updates, this may take a while…’ -PercentComplete -1
            $approvedupdates = Get-WsusUpdate -UpdateServer $WSUSserver -Approval Approved -Status InstalledOrNotApplicableOrNoStatus
            Write-Progress -Activity ‘Retrieved updates’ -PercentComplete 90

            $i = 0
            $superseded = $approvedupdates | ? {$_.Update.IsSuperseded -eq $true}
            $itanium = $approvedupdates | ? {$_.Update.Title -match “ia64|itanium”}
            $Sharepoint = $approvedupdates | ? {$_.Update.Title -match “SharePoint Enterprise Server|SharePoint Foundation|SharePoint Server|FAST Search Server”}
            $Win10x86 = $approvedupdates | ? {$_.Update.Title -match “Windows 10” -and $_.Update.Title -match “x86”}
            $Win10arm64 = $approvedupdates | ? {$_.Update.Title -match “Windows 10” -and $_.Update.Title -match “arm64”}
            $Officex86 = $approvedupdates | ? {$_.Update.Title -match “Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word” -and $_.Update.Title -match “32-Bit”}
            $Officex64 = $approvedupdates | ? {$_.Update.Title -match “Microsoft Office|Microsoft Access|Microsoft Excel|Microsoft Outlook|Microsoft Onenote|Microsoft PowerPoint|Microsoft Publisher|Microsoft Word” -and $_.Update.Title -match “64-Bit”}

            $totalsuperseded = $superseded.count
            $totalitanium = $itanium.count
            $totalSharepoint = $Sharepoint.count
            $totalWin10x86 = $Win10x86.count
            $totalWin10arm64 = $Win10arm64.count
            $totalOfficex86 = $Officex86.count
            $totalOfficex64 = $Officex64.count

            $datum = Get-Date -Format g

            foreach ($update in $superseded)
            {
            $datum + ” [Abgelehnt] ” + ” [Superseded] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $superseded)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalsuperseded) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $itanium)
            {
            $datum + ” [Abgelehnt] ” + ” [itanium] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $itanium)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalitanium) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Sharepoint)
            {
            $datum + ” [Abgelehnt] ” + ” [Sharepoint] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Sharepoint)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalSharepoint) * 100)
            $update.Update.Decline()
            $i++
            }
            $i = 0

            foreach ($update in $Win10x86)
            {
            $datum + ” [Abgelehnt] ” + ” [Win10x86] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Win10x86)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalWin10x86) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Win10arm64)
            {
            $datum + ” [Abgelehnt] ” + ” [Win10arm64] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Win10arm64)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalWin10arm64) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Officex86)
            {
            $datum + ” [Abgelehnt] ” + ” [Officex86] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Officex86)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalOfficex86) * 100)
            $update.Update.Decline()
            $i++
            }

            $i = 0

            foreach ($update in $Officex64)
            {
            $datum + ” [Abgelehnt] ” + ” [Officex64] ” + $update.update.title + “`r`n” | Out-File C:\WSUS_Skript_Bereinigung\Log\1LogAbgelehnteUpdates.txt -Append
            }

            foreach ($update in $Officex64)
            {
            Write-Progress -Activity ‘Declining updates’ -Status “$($update.Update.Title)” -PercentComplete (($i/$totalOfficex64) * 100)
            $update.Update.Decline()
            $i++
            }

            Write-Host “Total declined superseeded updates: $totalsuperseded” -ForegroundColor Yellow
            Write-Host “Total declined itanium updates: $totalitanium” -ForegroundColor Yellow
            Write-Host “Total declined sharepoint updates: $totalSharepoint” -ForegroundColor Yellow
            Write-Host “Total declined Windows 10 32bit updates: $totalWin10x86” -ForegroundColor Yellow
            Write-Host “Total declined Windows 10 arm64 updates: $totalWin10arm64” -ForegroundColor Yellow
            Write-Host “Total declined Office 32bit updates: $totalOfficex86” -ForegroundColor Yellow
            Write-Host “Total declined Office 64bit updates: $totalOfficex64” -ForegroundColor Yellow

            Invoke-WsusServerCleanup -DeclineSupersededUpdates -DeclineExpiredUpdates -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates

  2. Unser WSUS bat vorher 490 GB belegt, ich konnte durch das bereinigen der ersetzten Updates ca 400GB freischaufeln!

    Danke für den Tipp!

    Eine Frage habe ich aber noch zu dem Punkt:
    Weiter geht es an dieser Stelle und wir prüfen ob die Updates die die andere Ersetzen auch genehmigt wurden und zur Installation freigegeben sind.

    Wie prüfe ich das? Ich habe hoffnungsvoll ohne zu prüfen die Anleitung befolgt.

    Antworten
    • Hi Alex,
      schön das ich helfen konnte und 400GB bzw. ca. 82% ist schon eine ganze Menge. Ich habe den Artikel bzgl. deiner Frage etwas ausführlicher formuliert. Ich hoffe das hilft.

      Antworten
      • Danke für die Ergänzung !
        Ich habe noch auf einem weiteren WSUS Server die ersetzten Updates abgelehnt und den Server bereinigt. Ergebnis:
        Vorher ca 560GB belegt, jetz nur noch ca 55 GB ! 🙂

        Ich habe eben noch geprüft: Die Option “Updates automatisch ablehnen, wenn eine neue Revision deren Ablauf bewirkt” war bei uns seltsamerweise schon vorher aktiv…

        Ich habe irgendwo mal gelesen dass man die automatische Genehmigung von Updates noch besser organisieren kann indem man nur Updates genehmigt die auch von Clients angefordert/benötigt werden. Dadurch würden nicht erforderliche Updates auch gar nicht erst vom WSUS runtergeladen werden wodurch man wieder Platz sparen kann.

        Was mir noch beim aufräumen auffiel:
        Wenn ich zB gezielt Updates von Produkten die wir nicht mehr einsetzen ablehnen und somit löschen will, wie kann ich diese Updates eindeutig finden, ohne dabei auch jene Updates mit gelistet zu bekommen die gleichzeitig für andere Betriebssysteme sind?
        Beispiel: Ich will alle XP Updates entfernen und lasse mir diese Anzeigen mit einer exzra Updateansicht für Window XP Produkte. In der Liste stehen dann natürlich auch Updates wie für Windows XP, Server 2008 und Server 2008R2 sind.
        Server 2008R2 haben wir (noch) im Einsatz und möchten deswegen auch Updates erhalten.
        Ich könnte wohl zuerst alle XP ablehnen und dann das gleiche umgekehrt, also wieder genehmigen, mit Updates für 2008R2 machen?

        Antworten
        • Hi Alex,
          da wird doch echt HDD-Speicher frei :). Ich habe bis auf den Defender keine Updates als automatisch genehmigt. Ich handhabe es so, dass erst eine Testgruppe die neusten Updates erhält und wenn alles gut läuft, nach X-Tagen, alle anderen die Updates erhalten. D.h. Sie werden auch erst bei Genehmigung heruntergeladen und verbrauchen HDD-Speicher. D.h. heißt auch, dass ich Updates wie Office x64 ablehne, da nur x32 im Einsatz ist. Oder Updates für ARM oder älteren Windows Builds. Das hat auch den Vorteil, dass ggf. Updates die an dem Tag als “Fehlerverursachend” bekannt sind, erst Mal nicht genehmigt werden. Nachteil ist der höhere Aufwand…
          Zu deiner Windows XP Frage.
          – zuerst würde ich Windows XP aus “Produkte und Klassifizierung” in den Optionen deaktivieren, dann werden keine neuen runtergeladen
          – dann würde ich die Ansicht auf “alle bis auf abgelehnte” und Status “Alle” einstellen
          – nun die Suchfunktion verwenden und nach “Windows XP” suchen, nun werden dir entspr. alle mit “Windows XP” im Titel angezeigt
          – das Problem ist, dass viele Windows XP Updates auch für Windows Vista, Windows 7, Server 2003 und Server 2008 sind, heißt die brauchst du noch, aber alle anderen könntest du aus der Liste markieren und ablehnen
          – letztendlich noch ein weiteres händisches über die Liste der Updates schauen, ggf. erneut die Suchfuntkion verwenden um mehrere zu finden und aus der Liste abzulehnen
          – ist das getan, kannst du wie im Artikel beschrieben und von dir nun mehrfach durchgeführt, aufräumen 🙂

          Antworten
          • Mit Hilfe der Suche habe ich alle Updates für Itanium Systeme abgelehnt, da diese scheinbar wirklich immer exklusiv für Itanium-Systeme sind und somit keine anderen Betriebssysteme betroffen sind von meiner Aktion.
            Das Problem bei der Suche ist, dass nicht alle Updates unbedingt das Produkt im Titel haben. Ich habe das bei alten Office Updates für Version 2003 und/oder 2007 gesehen. Mit der Suchfunktion konnte ich sie nicht finden weil im Titel nur Stand “Office Update KBXYZ123 …” allerdings nicht die Versionsnummer (2003 oder 2007 zB)
            Evtl betrifft das auch nur einige alte Updates aber ich habe erstmal befürchtet und angenommen, dass das wohl generell nicht immer zwingend der vollständige Produktname (also Name + Version) im Titel steht. Ist halt mit Handarbeit verbunden aber geht auch irgendwie 😉

  3. Super Hilfe, konnte mit dieser Anleitung über 7010 Updates ablehnen und damit gerade 440 GB aus der WSUS-Datenbank auf einem 2012er entfernen. Vielen Dank, damit habe ich mir eine Erweiterung der Festplatte sparen können 😉

    Antworten
    • Gerne – gut das ich helfen konnte. Auf einem meiner neu betreuten Server sah es ähnlich aus. Aufräumen dauert dann zwar am Anfang lange, aber wenn man monatlich dabei bleibt, dann hält sich das in Grenzen und auf Dauer ist es performanter und bereitet weniger Problem, ganz zu schweigen, dass man auch mit dem Reporting vernünftig arbeiten kann. Für dein Angebot habe ich aktuell keine Zeit.

      Antworten

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.

Adblock Detected!

Taste-of-IT ist nur machbar, wenn auch die Werbung angezeigt wird. Wir versuchen hierbei diese so dezent wie möglich einzubinden, sodass der Besuch nicht beeinträchtigt wird. Unterstütze uns und setze Taste-of-IT.de in die Whitelist deines Browser. Vielen Dank