Powershell : désinstallation des hotfix Windows installés à une date spécifiée

J'ai développé pour le compte d'un collègue un script Powershell permettant de lister les hotfix Windows installés à une date spécifiée par l'utilisateur et proposant de les désinstaller, par exemple dans le cadre d'une campagne de patch mal déroulée sur une station ou un serveur.

Write-Host "Windows Operating System Hotfix KB remover"
Write-Host "==========================================`r`n"
$instdate = Read-Host "Please input the date KB were installed on."
$instdate = $instdate -as [datetime]
if($instdate -eq $null) { Write-Host "Please input a valid date.`r`nBye." ; exit }
$hotfixlist = Get-Hotfix | Where-Object { $_.InstalledOn -eq $instdate }
if($hotfixlist -eq $null) { Write-Host "No KBs installed for the specified date.`r`nBye." ; exit }
Write-Host "KB list for"$instdate
echo $hotfixlist
$choice = Read-Host "`r`nDo you want to uninstall those KBs ? (y to uninstall - any other input will cancel)"
if($choice -eq "y") {
foreach($kb in $hotfixlist){
$kbid = $kb.HotfixID.Substring(2,$kb.HotfixID.Length-2)
Write-Host "Uninstalling"$kbid
wusa.exe /uninstall /KB:$kbid /norestart
Write-Host "Please press ENTER only once the update wizard is closed because only one instance of it can be started at a time." -ForegroundColor "Yellow"
Read-Host
}
}
Write-Host "Bye."

Le script récupère la liste des patchs - Windows uniquement - installés le jour spécifié, extrait le numéro de KB et passe ensuite en argument de la ligne de commande de désinstallation de paquets Windows Update ce numéro en évitant un redémarrage.

Une pause marquée par le Read-Host est obligatoire après l'exécution de la commande de désinstallation sinon le script les exécute toutes à la suite, ce qui ne fonctionne pas puisque seule une instance de wusa.exe peut être lancée en même temps.

Une version commentée du script est disponible en téléchargement.

Powershell : reset de Windows Update

Toujours dans la lignée de la campagne de patchs pour Meltdown et Spectre, j'ai développé un script permettant d'effectuer les manipulations nécessaires à remettre le composant Windows Update en bon état de marche. Il arrive que le service Windows Update soit incapable de trouver des patchs à installer ou qu'il bute sur des erreurs lors de l'installation des patchs. Une fois qu'on a écarté les causes système habituelles (pas de contact du serveur WSUS, espace disque insuffisant sur le système, service non démarré...), il peut être nécessaire de supprimer les fichiers de Windows Update pour le forcer à reprendre comme si le serveur était fraîchement installé, sans que cela ne retire les patchs, bien évidemment.

J'ai donc développé un script en Powershell qui va couper les services, renommer - et pourquoi pas - supprimer ces répertoires. Comme toujours, le script est disponible dans une version commentée sur mon miroir de téléchargement.

echo "Stopping Cryptographic Service Provider."
net stop cryptsvc
echo "Stopping the Windows Update service."
net stop wuauserv
echo "Checking presence of .old directories."
if ((Test-Path C:\Windows\SoftwareDistribution.old) -eq $true) {
$delSD = Read-Host -Prompt "The script needs to delete C:\Windows\SoftwareDistribution.old which probably is a backup of the SoftwareDistribution folder. Type 'N' if you want to abort."
if ($delSD -eq 'N') {break}
Remove-Item C:\Windows\SoftwareDistribution.old -Force -Recurse
}
if ((Test-Path C:\Windows\System32\catroot2.old) -eq $true) {
$delCR = Read-Host -Prompt "The script needs to delete C:\Windows\System32\catroot2.old which probably is a backup of the catroot2 folder. Type 'N' if you want to abort."
if ($delCR -eq 'N') {break}
Remove-Item C:\Windows\System32\catroot2.old -Force -Recurse
}
echo "Renaming WindowsSoftwareDistribution to SoftwareDistribution.old"
$SD = $true
try {
Rename-Item -Path C:\Windows\SoftwareDistribution -NewName C:\Windows\SoftwareDistribution.old -ErrorAction Stop
}
catch {
echo "Folder doesn't exist, can't rename."
$SD = $false
}
echo "Renaming Windows\System32\catroot2 to catroot2.old"
$CR = $true
try {
Rename-Item -Path C:\Windows\System32\catroot2 -NewName C:\Windows\System32\catroot2.old -ErrorAction Stop
}
catch {
echo "Folder doesn't exist, can't rename."
$CR = $false
if ($SD -eq $false -And $CR -eq $false) {
echo "Both folders are missing. Aborting."
break
}
}
$delYN = Read-Host -Prompt "Do you want to delete the old folders ? The script will only do so if you answer 'Y'"
if ($delYN -eq 'Y')
{
if ($SD -eq $true) {Remove-Item C:\Windows\SoftwareDistribution.old -Force -Recurse}
if ($CR -eq $true) {Remove-Item C:\Windows\System32\catroot2.old -Force -Recurse}
}
echo "Starting the services previously stopped."
net start cryptsvc
net start wuauserv
echo "Done."

Erreur 800722E2 sur Windows Update

Durant ma campagne de patchs pour Meltdown et Spectre, j'ai été confronté à quelques serveurs qui me remontaient une erreur 800722E2 sur Windows Update.

Le service Windows Update était bien démarré, espace disque suffisant sur le système.

Par contre, l'ouverture de l'adresse du serveur WSUS dans un navigateur ne donnait rien sur le serveur, tandis que j'obtenais une erreur 403 sur mon poste local, ce qui signifie qu'à priori, le serveur ne communiquait pas avec le serveur WSUS (port 80).

Une vérification avec PortQuery de la fermeture et de l'ouverture des ports par la suite :

Windows Update a pu ensuite communiquer avec le WSUS et patcher le serveur correctement.

Powershell : vérification de l'installation d'un KB

Etant donné que je participe à la préparation d'une campagne de patchs suite aux failles Meltdown et Spectre, je me suis développé rapidement un script qui me permettra de vérifier si le(s) KB que nous allons installer l'auront bien été sur les systèmes en question.

Comme toujours, le script est téléchargeable dans une version commentée sur mon miroir de téléchargement.

Param
([string]$m,[string]$id)
$id = "KB"+$id
$KBlist = Get-Hotfix -ComputerName $m | Select HotfixID
foreach ($KB in $KBlist)
{
if ([string]$KB.HotfixID -ne $id){continue}
echo $id" effectif sur "$m
}

On exécutera simplement le script avec deux arguments :

.\win_kbcheck.ps1 -m <NomMachine> -id <NoDeKB>

Si le script ne retourne rien, c'est que le numéro de patch paramétré n'est pas installé sur la machine.

Charge CPU bloquée à 100% sur le serveur hébergeant les Office WebApps pour SharePoint 2013

Toujours dans la lignée de mon travail sur les serveurs WAC (Office WebApps pour SharePoint, voir ce précédent billet), j'ai été confronté à un problème de consommation CPU sur un des deux serveurs WAC ; le CPU était en charge maximale en permanence, même sans aucun appel des Office WebApps de la part des utilisateurs, un arrêt/relance des services et un redémarrage de la plateforme n'ayant rien changé.

svchost.exe consomme 100% du CPU

Le journal d'événements ne présentant aucune erreur particulière, je n'avais pas de piste à creuser, et le système semblait en bonne santé. Je décide alors de couper le service Windows Update qui n'a aucun impact sur le service rendu en production, et miracle :

La charge CPU retombe à des niveaux très faibles, ce qui est normal lorsque le WAC n'est pas sollicité. Dans mon environnement, laisser le service Windows Update désactivé n'est pas problématique car nous gérons à la main le patching des serveurs via des campagnes - il suffira de réactiver le service au moment de mettre à jour la machine et de le désactiver après si la consommation de CPU reste bloquée à 100%.