Bonjour à tous,
dans mon premier article sur WSUS et Powershell Wsus industrialisation du déploiement des mises à jour je vous suggérai un ensemble de script afin de gérer le déploiement de vos mises à jour ainsi que le traitement des indicateurs WSUS.
Je vais maintenant vous montrer comment lister l’ensemble des serveurs:
– en attente de redémarrage
– en erreur suite à l’installation de mise à jours
– n’ayant pas contacté WSUS depuis plusieurs jours
Je ne m’attarderai donc pas sur certaines commandes Powershell que nous pourrions déjà avoir vu ensemble lors de mon premier article lié à WSUS
Clients WSUS en attente de redémarrage
Récupération de la date du jour
$startTime = (get-date -f MM-dd-yyyy)
Récupération des informations du serveur WSUS local et déclaration du chemin d’un fichier csv
$wsus = Get-WsusServer $file = "\\Fileshare\WSUSTemp\Serveurs-Pending-Reboot-$startTime.csv"
On se crée un scope de recherche avec l’option « ::InstalledPendingReboot »
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null $computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope; $computerScope.IncludeDownstreamComputerTargets = $true $computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;
On vient ensuite utiliser ce scope via $wsus.GetComputerTargets. Si besoin vous pouvez utiliser la fonction Where-Object pour affiner votre recherche, dans notre exemple nous filtrons sur le nom de serveur avec « citrix ». Nous exportons le résultat dans le fichier CSV déclaré en début de script.
$computers = $wsus.GetComputerTargets($computerScope) | select FullDomainName,IPAddress | Export-Csv -Path $file $computers = $wsus.GetComputerTargets($computerScope) | Where-Object {$_.FullDomainName -like "*Citrix*"} | select FullDomainName,IPAddress | Export-Csv -Path $file $computers = $wsus.GetComputerTargets($computerScope) | Where-Object {$_.FullDomainName -like "*Citrix*"} | select FullDomainName
On récupère maintenant le nombre de serveur en attente de redémarrage
$count = $computers.count
Je déclare deux fichiers de communication HTM statique, un dans le cas ou il y a des serveurs en attente de redémarrage et un second dans le cas ou il n’y en aurai pas.
$file3 = "C:\Scripts\HTM\PendingReboot0\WSUS.htm" $file4 = "C:\Scripts\HTM\PendingReboot1\WSUS.htm"
Encoding en UTF8
$encoding=[System.Text.Encoding]::UTF8
On vient maintenant vérifier s’il y a bien une valeur au dessus de zero dans $count, si c’est le cas on envoi un mail avec la pièce jointe dans le cas contraire on envoi tout de même une communication mais évidemment sans pièce jointe
if ($count -eq "0"){ $body = Get-Content -Path $file3 | Out-String Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "Clients WSUS - Pas de redémarrage en attente" -SmtpServer "mail.ma-societe.fr" -bodyashtml -Body $body -Encoding $encoding } else{ $body = Get-Content -Path $file4 | Out-String Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "Clients WSUS - Des redémarrages sont en attente" -SmtpServer "mail.ma-societe.fr" -bodyashtml -Body $body -Attachments $file -Encoding $encoding }
Clients WSUS en erreur
Récupération de la date du jour
$startTime = (get-date -f MM-dd-yyyy)
Récupération des informations du serveur WSUS local et déclaration du chemin d’un fichier csv
$Wsus = Get-WsusServer $file = "\\Fileshare\WSUSTemp\Serveurs-en-erreur-$startTime.csv"
On déclare comme précédemment notre zone de recherche avec cette fois $updateScope.IncludedInstallationStates = ‘Failed’ et $computerScope.IncludedInstallationStates = ‘Failed’
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope $updateScope.IncludedInstallationStates = 'Failed' $computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope $computerScope.IncludedInstallationStates = 'Failed' $computerScope.IncludeDownstreamComputerTargets = 'true' $GroupFailHash=@{} $ComputerHash = @{} $UpdateHash = @{}
On vient maintenant rechercher pour l’ensemble des serveurs en erreur, toutes les KB avec le status d’installation en erreur également.
On peut toujours affiner si besoin la recherche via le filtre Where-Object {$_.FullDomainName -like « *citrix* »}
$ComputerFailInstall = $wsus.GetComputerTargets($computerScope) | Where-Object {$_.FullDomainName -like "*citrix*"} | ForEach { $Computername = $_.FullDomainName $Update = ($_.GetUpdateInstallationInfoPerUpdate($updateScope) | ForEach { $Update = $_.GetUpdate() $Update.title $Update.ProductTitles $ComputerHash[$Computername] += ,$Update.title $UpdateHash[$Update.title] += ,$Computername }) -join ', ' If ($Update) { $TempTargetGroups = ($_.GetComputerTargetGroups() | Select -Expand Name) $TempTargetGroups | ForEach { $GroupFailHash[$_]++ } [pscustomobject] @{ Computername = $_.FullDomainName TargetGroups = $TempTargetGroups IP= $_.IPAddress Updates = $Update } } }
Comme précédemment on vient récupérer le nombre de client correspondant
$count = $ComputerFailInstall.count
On déclare à nouveau deux fichiers HTM pour la communication
$file3 = "C:\Scripts\HTM\ServeursoenErreur0\WSUS.htm" $file4 = "C:\Scripts\HTM\ServeursenErreur1\WSUS.htm"
Encoding en UTF8
$encoding=[System.Text.Encoding]::UTF8
On vient maintenant comparer la valeur $count et renouveler l’opération si celle ci est > à zéro mais cette fois à la fin de la boucle nous utilisons « Out-File $file » qui vient remplir notre fichier CSV.
Je n’ai malheureusement pas trouvé l’astuce pour le faire en une seule fois, en effet, l’option « Out-File $file » empêche de réaliser un count derrière de la variable $ComputerFailInstall qui renvoi systématiquement un résultat nul.
if ($count -eq "0"){ $body = Get-Content -Path $file3 | Out-String Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "Serveurs WSUS - Pas de serveur en erreur $startTime" -SmtpServer "mail.ma-societe.fr" -Body $body -bodyashtml -Encoding $encoding } else{ $ComputerFailInstall = $wsus.GetComputerTargets($computerScope) | Where-Object {$_.FullDomainName -like "*CITRIX*"} | ForEach { $Computername = $_.FullDomainName $Update = ($_.GetUpdateInstallationInfoPerUpdate($updateScope) | ForEach { $Update = $_.GetUpdate() $Update.title $Update.ProductTitles $ComputerHash[$Computername] += ,$Update.title $UpdateHash[$Update.title] += ,$Computername }) -join ', ' If ($Update) { $TempTargetGroups = ($_.GetComputerTargetGroups() | Select -Expand Name) $TempTargetGroups | ForEach { $GroupFailHash[$_]++ } [pscustomobject] @{ Computername = $_.FullDomainName IP= $_.IPAddress TargetGroups = $TempTargetGroups Updates = $Update } } } | Sort Computername | Out-File $file -append -Width 3000 # Envoi du mail $body = Get-Content -Path $file4 | Out-String Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "Serveurs WSUS - Liste des serveurs en erreur $startTime" -SmtpServer "mail.ma-societe.fr" -Body $body -bodyashtml -Encoding $encoding -Attachments $file }
Clients WSUS n’ayant pas contacté WSUS depuis plusieurs jours
Déclaration de deux dates, celle du jour et celle du jour moins 4 jours
Tout en sachant qu’il doit le faire quotidiennement, on va partir du principe qu’un client qui ne contacte plus son serveur WSUS depuis plus de 4 jours rencontre un problème.
$startTime = (get-date -f yyyy-MM-dd) $startTime4 = (get-date).AddDays(-4).ToString("yyyy-MM-dd")
Déclaration d’un fichier sur lequel nous allons travailler
Utiliser la variable date dans le nom du fichier nous assure de ne jamais utiliser un doublon
$file = "\\Fileshare\WsusClientStatus-$startTime.csv"
On vient maintenant exporter au format CSV l’ensemble des serveurs dont le paramètre $_.LastReportedStatusTime est plus petit que J moins 4 jours, dans l’export on en profite pour ajouter le nom du client, sa date justement de dernier rapport, son appartenance à un groupe, et son IP. Je réalise de plus un tri sur le groupe des clients WSUS
Get-WsusComputer -IncludeDownstreamComputerTargets | Where-Object {$_.LastReportedStatusTime -le $startTime4} | select FullDomainName,LastReportedStatusTime,RequestedTargetGroupName,IPAddress | sort RequestedTargetGroupName| Export-Csv -Path $file -Delimiter ";"
Gérant plusieurs milliers de serveurs je n’ai jamais rencontré de cas où l’ensemble des clients WSUS contacte leur WSUS, j’ai constamment en moyenne quelques dizaines de serveurs posant problème. Je n’ai donc jamais eu besoin de compter cette valeur afin de pouvoir ensuite jouer sur la communication. Mais rien ne vous empêche de le faire en vous servant des exemples ci-dessus.
Comme toujours j’utilise un fichier HTM pour venir composer mon Email
$file3 = "C:\Scripts\HTM\Clients-WSUS-Pas-synchro\WSUS.htm" $encoding=[System.Text.Encoding]::UTF8 $body = Get-Content -Path $file3 | Out-String Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "Etat de synchro des serveurs reliés à WSUS" -SmtpServer "mail.ma-societe.fr" -bodyashtml -Body $body -Encoding $encoding -Attachments "$file"
Ces script permettent de rapidement visualiser les serveurs « en souffrance », il y a de très forte chance que vous soyez obligé de vous y connecter afin de les dépanner.
J’espère que ce deuxième article autour de WSUS vous a plu.
Évidemment beaucoup de chose sont modulables et également perfectibles !
Dans un prochain et dernier article autour de WSUS je tâcherai de rentrer cette fois dans la base SQL de WSUS toujours via PowerShell afin de sortir des rapports tels que les client WSUS avec des mises à jours approuvées en « need » ou plus simplement la liste de tous les clients et leur date de dernière synchronisation.
A+
Votre commentaire