TASTE-OF-IT

WSUS Server aufräumen und bereinigen

WSUS 3.0 Logo

WSUS 3.0 Logo

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
  • den Filter wie folgt einstellen:
  • WSUS Filter Settings
    1. Genehmigung: “Alle bis auf abgelehnte”
    2. Status: “Any”
    3. und auf “Aktualisieren” klicken
  • nun ggf. noch die Spalte “Ersatz” aktivieren
  • WSUS Spalte Ersatz
  • 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:

    SymbolErklärungAblehnen / Löschen
    WSUS Symbol kein Ersatz

    Dieses Update ersetzt andere Updates nein !

    WSUS Symbol Wird und ist Ersatz

    Dieses Update ersetzt ein Update, wird aber auch von einem anderen ersetzt. Ja

    WSUS Symbol Ersatz

    Dieses Update wird von einem anderen Update ersetzt. Ja

    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
  • hier nun entsprechend den eigenen Vorgaben, die entsprechenden Optionen auswählen, ich nehme alle, Beschreibung sollte selbsterklärend sein
  • 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:

    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:

    und los gehts:

    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

    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

    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

    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

    Have Fun …

    Die mobile Version verlassen