Crashs fréquents de WSUS 4.0

Depuis quelques jours, un serveur WSUS plantait au bout de quelques minutes de fonctionnement, sans dysfonctionnement notable côté système. Les logs de WSUS ne donnaient rien de particulier : toutes les requêtes y étaient journalisées, jusqu’au plantage sans code d’erreur particulier. Il suffisait d’un iisreset pour redonner l’accès au service, mais hors de question de créer un tâche planifiée pour effectuer un iisreset toutes les 5 minutes pour palier au dysfonctionnement.

Message d’erreur apparaissant sur la console WSUS peu de temps après le redémarrage du service.

J’avais cependant dans le journal d’événements Windows, deux entrées récurrentes, avec pour code d’erreur 5013 et 5138, et source « WAS ». Ces erreurs indiquent qu’une application utilisée dans le pool applicatif WsusPool n’a pas communiqué et ne s’est pas terminée dans le temps imparti.

J’ai procédé à quelques changements de variables concernant le pool applicatif WsusPool :

  • Queue Length : passage à 25000 au lieu de 5000 (il s’agit du nombre maximal de requêtes HTTP qui peuvent être en attente) ;
  • Augmentation de la Virtual Memory Limit à 5 Go (pour 8 installés physiquement sur le serveur) ;
  • Passage du « Service Unavailable » Response Type de HttpLevel vers TcpLevel : ceci permet d’éviter de renvoyer une erreur HTTP 503 Service Unavailable lorsque le serveur ne peut traiter la requête. Le serveur va à la place remettre en file d’attente la requête HTTP.

J’ai procédé ensuite à un redémarrage complet du serveur, WSUS fonctionne désormais depuis plus de 2 heures consécutives et aucun dysfonctionnement n’est à déplorer.

Powershell : Export CSV d’une liste de KB WSUS

Afin de pouvoir communiquer sur les KB qui devront être prochainement appliqués sur les stations de travail pilotes, j’ai réalisé un script permettant de récupérer la liste des patchs qui sont en statut FailedOrNeeded et qui sont Unapproved dans WSUS, avec un filtre supplémentaire appliqué plus tard sur le nom afin de rejeter ceux qui concernent les serveurs et le .NET Framework.

De plus, je souhaitais uniquement récupérer les mises à jour qui ne sont pas Superseded, signifiant qu’elles ne sont pas écrasées ou incluses dans d’autres patchs (par exemple, le KB numéro 12345 est un patch cumulatif et contient les KB 2345 et 4567, par conséquent je ne veux pas tester ces deux derniers mais uniquement 12345) ; ce qui force une double requête, transmise dans le pipe.

Write-Host "WSUS Updates CSV Export Script"
Write-Host "=============================="
Write-Host `r`n
Write-Host "Retrieving unapproved and failed or needed WSUS Updates.`r`nThis might take a couple of minutes..."
$output = @() 
$UpdateList = Get-WsusUpdate -Approval Unapproved -Status FailedOrNeeded -Classification All | Where {($_.Update.IsSuperseded -eq $false) -and ($_.Update.KnowledgeBaseArticles -ne $null) }
Write-Host "Filtering and exporting to CSV..."
foreach ($Update in $UpdateList) { 
    if ($Update.Update.Title.Contains("Server") -eq $false -and $Update.Update.Title.Contains("Framework") -eq $false){
        $title = $Update.Update.Title
        $kbnumber = $Update.Update.KnowledgeBaseArticles
        $product = $Update.Update.ProductTitles
        $classif = $Update.Update.UpdateClassificationTitle
        $date = $Update.Update.CreationDate
        $UpdatePSO = New-Object PSCustomObject
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Title" -Value $title
        $UpdatePSO | Add-Member -Type NoteProperty -Name "KB" -Value $kbnumber
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Product" -Value $product
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Class" -Value $classif
		$UpdatePSO | Add-Member -Type NoteProperty -Name "Date" -Value $date		
		$output+=$UpdatePSO
    }
}
$output | Export-CSV wsus-export-unapproved-failed.csv
Write-Host "Done."

J’ai choisi une séparation des colonnes avec un point-virgule car il y a des virgules dans les titres de certaines mises à jour ; il faudra donc veiller à bien spécifier que le point-virgule est le séparateur lors de l’ouverture du fichier CSV dans Excel. Ensuite, d’autres filtres sont possibles dans le tableur, on pourra donc exclure les mises à jour qui ne sont pas de sécurité par exemple.

Ce script, plutôt adapté à mon cas, peut être facilement modifié pour coller aux filtres que vous souhaitez appliquer, soit dans la requête WSUS de base, soit dans le foreach traité juste après.

Powershell : recyclage de pool WSUS à distance

J’avais déjà abordé la question de la consommation de RAM de WSUS à travers son pool applicatif IIS nommé WsusPool dans cet article ; j’ai décidé d’en faire un script Powershell afin de déclencher un recyclage du pool à distance.

Ce script va requêter le serveur via WinRM pour obtenir les informations concernant l’usage de la mémoire vive physique, et sur confirmation, déclencher à distance un recyclage du pool WsusPool.

function recycle{
Write-Host "Trying to start recycling in 5 seconds. Script will automatically end when recycling has successfully been initiated."
Start-Sleep 5
Invoke-Command -ComputerName $iishost -ScriptBlock { Restart-WebAppPool WsusPool }
}

Write-Host "WSUS IIS Application Pool Recycler"
Write-Host "=================================="
Write-Host ""
$iishost = Read-Host "Server to recycle the pool for ?"
$hostdetails = Get-Ciminstance Win32_operatingsystem -ComputerName $iishost
$hostramtotal = $hostdetails.TotalVisibleMemorySize
$hostramused = $hostdetails.TotalVisibleMemorySize - $hostdetails.FreePhysicalMemory
$hostramperc = [math]::Round(($hostramused/$hostramtotal)*100,0)
$hostramtotal = [math]::Round($hostdetails.TotalVisibleMemorySize/1048576,0)
Write-Host "% RAM used: $hostramperc"
Write-Host "Server $iishost has $hostramtotal GB total memory."
$confirm = Read-Host "Please confirm you wish to recycle the WsusPool IIS Application Pool on $iishost (yes)"
if ($confirm -eq "yes") { recycle }
else { Write-Host "Bye." ; break }

Au final, il est possible d’utiliser ce script pour n’importe quel pool car la commande Restart-WebAppPool est liée à IIS et pas spécialement à WSUS.

Réguler la consommation de RAM sur un serveur WSUS

Il arrive que WSUS et IIS qui fonctionnent de pair puissent déclencher fréquemment des alertes de sur-consommation de mémoire vive. Bien que cela n’impacte pas forcément les performances dudit serveur, il peut être nécessaire de forcer une « purge » du processus IIS exécutant le pool applicatif de WSUS afin que la consommation en RAM redescende.

Par exemple, ce matin :

Dans IIS, on peut « forcer » le pool applicatif de WSUS simplement nommé WsusPool à faire un recyclage des ressources systèmes qu’il occupe. Il suffit de sélectionner ce pool et de cliquer sur les options de recyclage (et non l’action de recyclage elle-même avec son icône de flèches vertes). Une fenêtre s’ouvre alors, proposant diverses options :

La fenêtre des options de recyclage permet de choisir une échéance de temps, de nombre de requêtes ou de consommation de mémoire vive, ou plusieurs à la fois.

On choisit donc les options qui nous conviennent : dans mon cas, en plus de l’intervalle de temps entre deux recyclages, j’ai défini un maximum de mémoire vive (à adapter en fonction de la charge souhaitée sur le serveur, il est évident que si l’on décide de n’y allouer que 500 Mo, les performances vont en pâtir), mais c’est optionnel. Une fois ce choix validé, nous pouvons lancer à la main un recyclage :

IIS va donc recycler le pool : cela signifie qu’il va créer un autre processus exécutant ce pool, puis transférer la charge mémoire du premier vers le nouveau, en faisant le « ménage » parmi ce dont il n’a plus besoin.

Le recyclage est en cours, le premier processus se vide en faveur du deuxième avant de disparaître.

Ainsi, la consommation en RAM a bien chuté et ne pourra dépasser 4 Go. Bien évidemment, cette limite n’est pas obligatoire ; en cas de surcharge ponctuelle du serveur, on peut toujours déclencher un recyclage manuel qui aura le même effet.