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.

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.

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

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.

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 ""
Write-Host "Retrieving unapproved and failed or needed WSUS Updates.`r`nThis might take a couple of minutes..."
$CsvFileDump = "wsus-export-unapproved-failed.csv"
try { Clear-Content -path $CsvFileDump -Force -ErrorAction SilentlyContinue }
catch { Write-Host "No previous dump file has been detected in script folder." }
$CsvHeader = "No. de KB;Description;Produit;Classification;Date de publication"
Add-Content -Value $CsvHeader -Path $CsvFileDump
$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
$CsvRow = "$kbnumber;$title;$product;$classif;$date"
Add-Content -Value $CsvRow -Path $CsvFileDump
}
}
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.