Grundsätzliches bei SBS-Themen
Der SBS2011 ist „nicht ohne“ und verkommt bei schlechter Behandlung zur wiederlichsten Zicke, die Sie in ihrem Leben getroffen haben.
Wenn Sie sich „nur“ mit Computern oder Windows auskennen: Lassen Sie um Himmels Willen die Finger von allem, was außerhalb der „Small Business Standard Konsole“ abläuft. Bitte denken Sie ernsthaft darüber nach, diese Aufgabe (und die Verwantwortung!) zu delegieren.
Wenn Sie sich mit Windows Server 2008r2 und dem Microsoft SQL Server auskennen: Bitte lesen Sie diese Anleitung vollständig und handeln Sie erst dann, wenn Sie der Meinung sind, alles verstanden zu haben.
Die Bereinigung nimmt durchaus mal ein paar Tage Zeit in Anspruch. Das ist aber nicht weiter dramatisch, da das letztendlich im Hintergrund abläuft und die Ressourcenbelastung „eher moderat“ ist.
Meiner Erfahrung nach kann man das durchaus im Geschäftsbetrieb durchführen. Zumindest haben meine Kunden noch nie etwas davon mitbekommen 🙂
Problembeschreibung
Der WSUS-Server vom SBS2011 bzw. 2008r2 „hakt“. Entweder, er liefert gar keine Updates mehr aus oder er holt keine neuen Updates. Der Assistent zur Serverbereinigung läuft auf einen Timeout hinaus.
Was machen wir?
Wir werden den WSUS-Server bzw. dessen Datenbank entschlacken. Gerade bei älteren Systemen wächst diese durchaus auf mehrere Gigabyte an und bremst die Mühle bis zum Stillstand herunter. Erschwerend hinzu kommt beim SBS2011, dass das zugrundeliegende Betriebssystem maximal 32GB RAM verwalten kann. Irgendwann ist also definitiv „Ende Gelände“.
Natürlich werden wir eine Menge löschen, was aber nicht dramatisch ist.
Bei der Aufräumaktion geht es primär darum, historische Protokolle, Statistiken, zurückgezogene oder aus anderen Gründen obsolete Updates zu löschen.
Ab in die Datenbank
Im Startmenü unter „Microsoft SQL Server 2008 R2“ das „SQL Management Studio“ starten und mit dem Datenbankmodul
\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query
verbinden (Windows-Authentifizierung). Hier ein Screenshot vom Anmeldefenster:
Schritt 1: Löschen der Synchronisationshistorie
Wir klicken auf „Neue Abfrage“. Zum Löschen geben wir diesen Text in das Abfragefenster ein:
USE SUSDB GO DELETE FROM tbEventInstance WHERE EventNamespaceID = '2' AND EVENTID IN ('381', '382', '384', '386', '387', '389')
Auch wenn es verleitet: Der „! Ausführen“ Button ist der mit dem roten Ausrufezeichen und nicht der Button mit dem grünen Pfeil.
Wir klicken also auf „! Ausführen“ und erhalten wenige Sekunden später das Ergebnis der Löschaktion.
Schritt 2: Löschen aller obsoleten Updates
Bitte das folgende Script im Abfragefenster eingeben:
DECLARE @var1 INT DECLARE @msg nvarchar(100) CREATE TABLE #results (Col1 INT) INSERT INTO #results(Col1) EXEC spGetObsoleteUpdatesToCleanup DECLARE WC Cursor FOR SELECT Col1 FROM #results OPEN WC FETCH NEXT FROM WC INTO @var1 WHILE (@@FETCH_STATUS > -1) BEGIN SET @msg = 'Deleting ' + CONVERT(varchar(10), @var1) RAISERROR(@msg,0,1) WITH NOWAIT EXEC spDeleteUpdate @localUpdateID=@var1 FETCH NEXT FROM WC INTO @var1 END CLOSE WC DEALLOCATE WC DROP TABLE #results
Auch hier wieder aus „Ausführen“ klicken. Achtung – dieses Script kann tatsächlich Tage(!) laufen. Aber, keine Angst: Die Serverbelastung durch das Script ist moderat, die Performancebelastung ist nicht bemerkbar.
Dass es noch läuft, sehen wir an der Statusleiste:
Wenn das Script durchgelaufen ist, sieht das Ganze so aus:
Es ist sehr warscheinlich, dass nicht alle Updates gelöscht wurden (z.B. dann, wenn nach der Ausführung bis zur Betrachtung des Ergebnisses eine erneute Synchronisation stattgefunden hat).
Ob wir fertig sind, überprüfen wir mit dieser Datenbankabfrage:
USE SUSDB GO exec spGetObsoleteUpdatesToCleanup
Wenn unten im Ergebnisfenster eine Liste mit Nummern angezeigt wird, führt man das Script zum Löschen der obsoleten Updates erneut aus.
Das Ganze machen wir so lange, bis „der Dreizeiler“ keine Updates mehr anzeigt.
Schritt 3: Reindizierung der Datenbank
Der Index der Datenbank (also das „Was steht wo?“) wird anhand des aktuellen Datenbankinhaltes komplett neu aufgebaut.
Hier das passende Script für das Abfragefenster vom SQL-Studio:
/ This sample T-SQL script performs basic maintenance tasks on SUSDB 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 Updates potentially out-of-date table statistics. / USE SUSDB; GO SET NOCOUNT 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
Für die Laufzeit würde ich maximal 2 Stunden einkalkulieren. Auch hier ist die Systemauslastung eher moderat.
Schritt 4: Verzeichnis aufräumen
Die ganzen Updates „liegen ja irgendwo auf der Platte“ und das Verzeichnis mit dem Inhalt kann tatsächlich enorme Ausmaße beanspruchen.
Um das Verzeichnis aufzuräumen, bediene ich mich eines Powershell-Scriptes.
Performs a cleanup of WSUS. Outputs the results to a text file. Adapted and tested by BigTeddy 3 July 2012 $outFilePath = '.\wsusClean.txt' [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer(); $cleanupScope = new-object Microsoft.UpdateServices.Administration.CleanupScope; $cleanupScope.DeclineSupersededUpdates = $true $cleanupScope.DeclineExpiredUpdates = $true $cleanupScope.CleanupObsoleteUpdates = $true $cleanupScope.CompressUpdates = $true $cleanupScope.CleanupObsoleteComputers = $true $cleanupScope.CleanupUnneededContentFiles = $true $cleanupManager = $wsus.GetCleanupManager(); $cleanupManager.PerformCleanup($cleanupScope) | Out-File -FilePath $outFilePath
Zur Ausführung des Scriptes speichert man dieses unter einem einprägsamen Namen (z.B. „WSUS-Cleanup.ps1“) und startet eine Powershell als Administrator.
Danach wechselt man in das Verzeichnis mit dem Script, startet es und findet im gleichen Ordner nach erfolgter Ausführung die Datei wsusClean.txt mit dem Ergebnis:
SupersededUpdatesDeclined : 7 ExpiredUpdatesDeclined : 0 ObsoleteUpdatesDeleted : 0 UpdatesCompressed : 19717 ObsoleteComputersDeleted : 0 DiskSpaceFreed : 46590272
Zugegeben: Der Speicherplatzgewinn ist in diesem Beispiel nicht sooooo dramatisch. Aber vielleicht hängt das ja auch damit zusammen, dass ich diese Anleitung kurz nach einer erfolgreichen Bereinigung geschrieben habe 🙂
Eine Antwort auf „WSUS auf einem SBS2011 reparieren (Timeout)“
Servus,
ich möchte mich bei deinen Artikel bedanken, er hat mir letztendlich bei meinen WSUS Problem geholfen.
Zwei Anmerkungen habe ich, bei mir hat es leider nicht ganz von Anfang an funktioniert, da ich mich nicht mit der Datenbank verbinden konnte.
Nach langer Recherche musst ich noch folgendes vorher im SQL Server Konfiguration Manager aktivieren:
SQL Server-Netzwerkkonfiguration > Protokolle für SQL Express > NamesPipes
Wir haben einen Windows Server 2016 & 2019 mit WSUS. Vielleicht kannst du ggf. den Artikel auch für diese beiden Server Systeme aktualisieren. Ich denke es hilft vielen Menschen. Dein Artikel funktioniert und hilft.
vielen vielen Dank
Grüße Basti