WSUS - Correction des crashs lors du nettoyage

CréationNicolas THOREZ 2020/07/30 10:01

Lors du nettoyage de la base de données de WSUS, il peut arriver que des erreurs de connexions empêchent le processus d'aller jusqu'au bout.

Exemple d'erreur pour un nettoyage via la console

Exemple d'erreur pour un nettoyage via powershell

Ce problème survient quand la base est trop sollicitée, voire endommagée/fragmentée.

Attention

Les commandes suivantes sont à exécuter en tant qu'administrateur. Par conséquent, faîtes très attention à ce que vous faîtes.

Cette solution consiste à arrêter et redémarrer WSUS (pour réinitialiser son utilisation) et à lancer les opération de nettoyage une par une.

Restart-Service -Name WsusService
Restart-Service -Name WSusCertServer
Get-WsusServer | Invoke-WsusServerCleanup -CleanupUnneededContentFiles
Get-WsusServer | Invoke-WsusServerCleanup -CompressUpdates
Get-WsusServer | Invoke-WsusServerCleanup -DeclineSupersededUpdates
Get-WsusServer | Invoke-WsusServerCleanup -DeclineExpiredUpdates
Get-WsusServer | Invoke-WsusServerCleanup -CleanupObsoleteComputers
Get-WsusServer | Invoke-WsusServerCleanup -CleanupObsoleteUpdates

Si aucun message d'erreur n'apparaît, la base WSUS est alors nettoyé complètement, sinon, c'est qu'elle est endommagée/fragmentée et il faut donc passer à la solution 2.

Cette solution consiste à réparer, défragmenter et ainsi opytimiser la base afin d'éviter les erreurs et les timeout. On commence donc par créer un script SQL. Dans l'exemple, le fichier s'appellera WsusDBMaintenance.sql et sera enregistré dans le dossier C:\Temp\.

  • On crée le fichier C:\Temp\WsusDBMaintenance.sql contenant le code suivant :

/******************************************************************************
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;

-- 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

  • Depuis une invite de commande, on exécute le commande suivante :

sqlcmd -I -S \\.\pipe\MICROSOFT##WID\tsql\query -i C:\Temp\WsusDBMaintenance.sql

  • Une fois terminée (le temps d'exécution peut varier selon la taille, les dommages, la fragmentation, etc, de la base), vous pouvez réappliquer la solution 1.

Cette solution peut être un peu longue (dépend de la date de la dernière maintenance) mais a le mérite de toujours fonctionner.

  • On commence par l'ancer l'interface de WSUS et on va dans le menu Toutes les mises à jour, où on affichera toutes les mises à jour approuvées :
  • On fait un clic droit sur la barre de catégorie de la liste afin d'afficher la catégorie Remplacement :
  • La catégorie Remplacement apparait donc. On cliquera dessus afin de classer toutes les mises à jour selon ce critère :
  • Les différentes mises à jour peuvent être classées dans 4 catégories :
    • Cette mise à jour remplace d'autres mises à jour.
    • Cette mise à jour est remplacée par une autre mise à jour et remplace d'autres mises à jour.
    • Cette mise à jour est remplacée par une autre mise à jour.
    • Aucune icone : Cette mise à jour est toute seule dans sa chaîne de mise de jour (généralement des applications ou service pack).
  • On sélectionnera donc toutes les mises à jours remplacées (les et les ) puis on les refusera (clic droit, option Refuser) :
  • Il nous reste plus qu'à lancer la maintenance (menu Options et Assistant de nettoyage du serveur ) :
  • On ne choisira que l'option Fichiers de mise à jour inutiles avant de cliquer sur Suivant > :
  • A la fin de la maintance, l'espace libéré s'affiche :

Afin d'éviter les problèmes de WSUS, une maintenance régulière est préférable. Il est donc recommandé d'activer une tâche planifiée pour effectuer les opérations de nettoyage une fois par semaine.

Entrer votre commentaire. La syntaxe wiki est autorisée:
 
  • wsus_repaircleanup.txt
  • Dernière modification : 2021/03/05 14:16
  • de nekan