WSUS by Powershell. Industrialisation du déploiement des mises à jour et Indicateurs

Bonjour à tous,

j’avais envie aujourd’hui de vous montrer comment automatiser et industrialiser l’approbation automatique et donc l’application de patch Microsoft pour vos serveurs Windows.

en effet, suite à l’arriver des différents Cryptolocker qui nous menace maintenant quotidiennement, j’ai due, au sein de l’entreprise pour laquelle je travaille, passer des semaines, pour améliorer la gestion des patch Microsoft et surtout faire en sorte que ce qui était fait à la main auparavant ne le soit plus afin de diminuer le risque d’erreur humaine. Effectivement, nous nous sommes rendu compte que le fait d’oublier d’approuver des patch de sécurité Microsoft par mégarde ou parceque le process n’est pas assez clair, pouvait mettre en péril les données d’un nombre conséquent de serveur que l’on héberge.

Cet article ne sera pas porté sur l’installation ni même le paramétrage WSUS mais sur la gestion des mises à jours et leur distribution au sein de votre parc informatique. Cet article sera donc plus compréhensible par un administrateur connaissant déjà bien l’outil et qui le manipule de façon régulière.

Les scripts powershell que je vais vous présenter sont spécifiques à mon entreprise, à notre infra et aussi à notre besoin mais ils vous permettront, d’avoir une bonne base s’il s’avère que vous puissiez être amené à utiliser powershell pour gérer WSUS; ce que je vous conseille fortement pour avoir toute la souplesse que l’on va découvrir ensemble par la suite.

Je vais vous montrer:

  • comment lancer une synchronisation WSUS, récupérer les informations de synchronisation et les injecter dans une page web ou dans un fichier excel
  • comment récupérer la liste des mises à jours et les indicateurs du Tuesday Patch
  • comment approuver des mises à jours pour des groupes WSUS spécifiques
  • comment exporter le résultat de vos filtres dans un fichier au format CSV
  • comment envoyer des mails avec contenu au format HTM

Dans un premier temps, je voulais vous préciser pourquoi je ne me suis pas servi de la fonction « Règle d’approbation automatique » que l’on retrouve dans la console de gestion WSUS pour approuver les patch Microsoft. Puisque tous mes scripts parte de ce qui va suivre, j’aurai finalement plus appeler cet article « Règles d’Approbation automatique versus Powershell approbation ».

La raison est double,

  • d’une part, lorsque vous synchronisez votre serveur WSUS à Windows update, vous récupérer une liste de nouvelles mises à jours. Si la règle d’approbation automatique que vous avez créée « match » avec l’une des nouvelles mises à jours récupérées, alors celle ci sera automatique approuvée une fois la synchronisation terminée et donc mis à disposition des serveurs impactés par la Règle d’approbation automatique.

Cela me dérange dans le sens où je souhaite pouvoir synchroniser mon WSUS à Windows Update sans forcément lancer une processus d’approbation dans la foulé. En effet je souhaite décider quand approuver les patch et donc leur téléchargement.

  • D’autre part, si vous avez une infra WSUS multi serveurs comme la notre, avec un serveur WSUS parent et un ou plusieurs serveurs WSUS enfants, vous devez déjà savoir que les informations des serveur WSUS enfants seront à jour coté WSUS parent uniquement après synchronisation de deux parties.

En effet si vous ne synchronisez par souvent, vous verrez régulièrement un décalage entre le WSUS parent et le WSUS enfant. Par exemple des clients wsus absents, des groupes non présents, des dates de dernier rapport fausses etc…un peu à la manière de la console SCVMM et des host Hyper-V, si vous n’actualisez pas les hosts\machines virtuelles régulièrement pas votre console n’est pas à jour!

L’idéal est donc de tout gérer à partir du serveur parent, d’utiliser une seule console WSUS.

Venons en maintenant au premier script celui qui va lancer la synchronisation de notre WSUS

#récupération des informations WSUS via la commande Get-Wsusserver puis lancement de la synchro avec « StartSynchronization() »

(Get-WsusServer).GetSubscription().StartSynchronization()

# on créée une Variable qui va récupérer la date du jour au format français

$startTime = (get-date -f dd-MM-yyyy)

#on force l’encoding en UTF8 pour gérer les accents dans le mail

$encoding=[System.Text.Encoding]::UTF8

# envoi d’un e-mail avec send-mailmessage

Send-MailMessage -From "wsus@masociete.fr" -To "equipe.microsoft@masociete.fr" -Subject "WSUS - Synchro hebdo lancée $startTime" -SmtpServer "mail.masociete.fr" -Body "WSUS - Synchronisation hebdo lancée" -Encoding $encoding

Ce petit script permet sans avoir à se connecter nulle part, d’être avertit que la synchronisation a été lancé. Pour notre part, nous synchronisons deux fois par semaine WSUS. Le mardi et le vendredi. Le mardi soir permet de récupérer les KB du Tuesday Patch Microsoft (2eme mardi du mois) le plus tôt possible et le vendredi afin d’avoir au moins deux synchronisation par semaine avec les WSUS Downstream.

Regardons maintenant via un second script comment récupérer les informations de synchronisation.
J’entends par là le nombre de nouvelles mises à jours, celles révisées et celles expirées également.

# On récupère dans la variable $Lastsync les informations de la dernières synchronisation WSUS

$lastSync = (Get-WsusServer).GetSubscription().GetLastSynchronizationInfo()

# On va définir un scope afin de récupérer uniquement les mises à jours de cette synchro

$UpdateScope = New-Object -TypeName Microsoft.UpdateServices.Administration.UpdateScope

# Définir un créneau horaire afin de récupérer uniquement les mises à jours de la dernière synchronisation avec une date de début et une date de fin

$UpdateScope.FromArrivalDate = $lastSync.StartTime
$UpdateScope.ToArrivalDate = $lastSync.EndTime

# On récupère cette liste de KB en fonction de l’UpdateScope que l’on vient de configurer.

$SyncUpdates = (Get-WsusServer).GetUpdates($UpdateScope)

# On récupère depuis la variable $SyncUpdates les nouvelles Mises à jours et on les compte

$published = $SyncUpdates | where {($_.publicationstate -like "Published")}
$published.count

# On récupère depuis cette liste les Mises à jours révisées et on les compte

$revised = $SyncUpdates | where {($_.publicationstate -like "revised")}
$revised.count

# On récupère depuis cette liste les Mises à jours expirées et on les compte

$expired = $SyncUpdates | where {($_.publicationstate -like "expired")}
$expired.count

# On récupère la liste de tous les clients WSUS rattachés à nos WSUS (serveurs Wsus parent et enfants grâce à IncludeDownstreamComputerTargets) et on fait le compte

$wsus = Get-WsusServer
$computers = $wsus | Get-WsusComputer -IncludeDownstreamComputerTargets
$computers.count

Pour l’envoi de nos mails nous utilisons en body un fichier HTM. Cette base de format nous permet de réaliser des ajouts à chaud ou simplement d’écrire des choses en dure et de le laisser static.
Le rendu est agréable à visionner (enfin je trouve ^^)

J’ai du coup un fichier HTM par besoin\fonction – Si le fichier HTM est temporaire c’est à dire avec des données que j’injecte seulement à l’instant T comme c’est le cas dans notre exemple je pars d’un Template que je copie, que je complète, que j’envoie puis que je supprime.

# Copie du fichier HTM Temporaire

xcopy /s "C:\Scripts\HTM\IndicateurWSUS\TEMPLATE\*.*" "C:\Scripts\HTM\IndicateurWSUS\"

# Une fois le fichier copié, on déclare le chemin correspondant à notre fichier temporaire.

$Filehtm = "C:\Scripts\HTM\IndicateurWSUS\WSUS.htm"

# On récupère via get-content le contenu du HTM et on y injecte les données des variables précédemment récupérées. L’ajout de donnée se fait vers des numéros de lignes biens spécifique que l’on a préparée en amont.

$fileContent = Get-Content $Filehtm
$fileContent[966] += $computers.count
$fileContent[979] += $published.count
$fileContent[993] += $revised.count
$fileContent[1008] += $expired.count
$fileContent[1023] += $update.count
$fileContent | Set-Content $filehtm

# Une fois notre fichier HTM « mis à jour » avec les données qui vont biens on configure le body du mail comme étant le contenu du fichier HTM.

$body = Get-Content -Path $filehtm | Out-String

# on se positionne en encoding UTF8 afin de gérer les accents que ce soit dans le Subject ou le Body du mail que l’on va envoyer.

$encoding=[System.Text.Encoding]::UTF8

# On positionne la date dans une variable avec le format qui nous intéresse

$startTime = (get-date -f dd-MM-yyyy)

# Envoi du mail via send-mailmessage, l’option -bodyashtml permet d’indiquer que l’envoi de mail utilise un body en mode HTML afin qu’il puisse être correctement interprété

Send-MailMessage -From "wsus@societe.fr" -To "equipe.microsoft@societe.fr","m.jouan@societe.fr" -Subject "Indicateur WSUS - Etat Synchro du Tuesday Patch datant du $startTime" -SmtpServer "mail.masociete.fr" -Encoding $encoding -Body $body -bodyashtml

# On peut exécuter une pause de 5s si besoin via la commande ping.

ping -n 5 127.0.0.1

# Comme expliqué un peu plus haut on supprime le fichier HTM qui a été généré à partir du template

rm "C:\Scripts\HTM\IndicateurWSUS\WSUS_fichiers\" -r -force
rm "C:\Scripts\HTM\IndicateurWSUS\WSUS.htm"

Comment trouvez vous le résultat ? J’ai masqué nos photos mais je vous assure que ce système de communication est appréciable en plus d’être assez simple à prendre en main

Nous pourrions nous arrêter là mais j’ai eu envie d’aller plus loin :), nous allons maintenant pousser ces indicateurs dans un fichier excel
Mais qui dit fichier Excel dit arborescence Windows, la notre ressemble à beaucoup d’autres: « \\Production\Qualité\2018\Indicateurs-2018-02.xls », vous l’aurez compris il va donc falloir jouer avec les mois et les années.
Nous utilisons un seul et même fichier mensuel pour l’ensemble des indicateurs de la société, WSUS on a donc sa propre feuille Excel nommée « WSUS »

Avant de pouvoir remplir mensuellement mon Excel de façon automatisé, j’ai d’abord fait en sorte de gérer le mois et l’année que ce soit dans le path comme dans le nom du fichier lui-même.

# Je déclare donc plusieurs variables afin de récupérer ces deux valeurs

$startTime = get-date
$startTime.Year
$startTime.Month

# Je continue dans la déclaration de variable afin d’être sur ce qu’on appelle du long terme…

if($startTime.Year -like '2018'){$year='2018'}
if($startTime.Year -like '2019'){$year='2019'}
if($startTime.Year -like '2020'){$year='2020'}
if($startTime.Year -like '2021'){$year='2021'}
if($startTime.Year -like '2022'){$year='2022'}
if($startTime.Year -like '2023'){$year='2023'}
if($startTime.Year -like '2024'){$year='2024'}
if($startTime.Year -like '2025'){$year='2025'}
if($startTime.Year -like '2026'){$year='2026'}
if($startTime.Year -like '2027'){$year='2027'}
if($startTime.Year -like '2028'){$year='2028'}
if($startTime.Year -like '2029'){$year='2029'}
if($startTime.Year -like '2030'){$year='2030'}

if($startTime.Month -like '1'){$month='01'}
if($startTime.Month -like '2'){$month='02'}
if($startTime.Month -like '3'){$month='03'}
if($startTime.Month -like '4'){$month='04'}
if($startTime.Month -like '5'){$month='05'}
if($startTime.Month -like '6'){$month='06'}
if($startTime.Month -like '7'){$month='07'}
if($startTime.Month -like '8'){$month='08'}
if($startTime.Month -like '9'){$month='09'}
if($startTime.Month -like '10'){$month='10'}
if($startTime.Month -like '11'){$month='11'}
if($startTime.Month -like '12'){$month='12'}

# Je peux maintenant déclarer mon chemin correspondant au mois et à l’année en cours

$path = "\\Production\Qualité\$year\tdb_"+$year+"_"+$month+".xls"

# Je vérifie via test-path si le fichier excel que je veux remplir existe, si ce n’est pas le cas je viens copier celui du mois précédent.

if (Test-Path $path){} else {
$monthlessnew = $month - 1
$monthlessnew = "{0:D2}" -f $monthlessnew
$pathless = "\\Production\Qualité\$year\tdb_"+$year+"_"+$monthlessnew+".xls"
copy $pathless $path
}

# On récupère la valeur qui vérifie si le fichier Excel est verrouillé ou accessible (true ou False)

$FILE = try { [IO.File]::OpenWrite($path).close();$true }catch {$false}

# Si inaccessible car déjà ouvert, on envoi un mail pour informer que les indicateurs n’ont pu être ajouté automatiquement, sinon on les ajoute au fichier excel

if ($FILE -like "False"){

# J'ai créée un fichier txt avec le chiffre indiquant le numéro de la colonne sur laquelle je vais compléter mes cellules
# Je vous rappelle avoir souhaité tout automatiser, c'était auparavant fait manuellement, je sais cependant aujourd'hui que les indicateurs du mois en cours 02/2017 devront arriver dans la colonne 27
# Avec Excel pour cibler la bonne colonne vous devez retirer 1, dans mon cas je dois donc utiliser 26. Si vous avez bien suivi c'est pourtant la colonne Excel qui à ce jour est déjà complétée et comporte les valeurs du mois de Janvier 2018.
# Je récupère donc la valeur actuelle de mon fichier txt qui est "26"
# Nous nous situons dans la partie du script où le fichier excel est actuellement verrouillé, j’envoie donc simplement un mail pour signaler le blocage et j'incrémente également mon numéro de colonne pour l'exécution de ce script le mois prochain

$colonn = get-content C:\Scripts\colonne.txt
$colonne = [int]$colonn + 1
$colonne > C:\Scripts\colonne.txt
$startTime = (get-date -f MM/yy)

Send-MailMessage -From "wsus@masociete.fr" -To "equipe.microsoft@masociete.fr","m.jouan@masociete.fr" -Subject "Indicateur WSUS - Fichier Excel verrouillé - $startTime" -SmtpServer "mail.masociete.fr" -Encoding $encoding -bodyashtml

} else {

# On est dans la section ou le fichier excel est accessible
# Je peux configurer mes variables qui vont me permettre d'ouvrir mon fichier Excel en indiquant bien via WorkSheets.item la feuille Excel sur laquelle je souhaite travailler.
$xl=New-Object -ComObject Excel.Application
$wb=$xl.WorkBooks.Open($path)
$ws=$wb.WorkSheets.item("Wsus")
$xl.Visible=$true

$startTime = (get-date -f MM/yy)

# on Récupère la valeur de la colonne à traiter
$colonn = get-content C:\Scripts\colonne.txt

# Je peux maintenant positionner les valeurs dans les cellules correspondantes à la bonne colonne.
$ws.Cells.Item(2,$colonn)=$startTime
$ws.Cells.Item(3,$colonn)=$computers.count
$ws.Cells.Item(4,$colonn)=$published.count
$ws.Cells.Item(5,$colonn)=$revised.count
$ws.Cells.Item(6,$colonn)=$expired.count
$ws.Cells.Item(7,$colonn)=$update.count

# J'ajoute maintenant '1' à la valeur précédente qui était "26"
$colonne = [int]$colonn + 1
# Je viens ensuite réinjecter cette nouvelle valeur dans mon fichier d'origine afin que l’exécution du script le mois prochain utilise la colonne suivante
$colonne > C:\Scripts\colonne.txt

# Nous reste plus qu'à sauvegarder nos modifications puis à quitter.
$wb.Save()
$wb.close()
$xl.Quit()

# On termine en indiquant par mail que le fichier excel a bien été complété

Send-MailMessage -From "wsus@societe.fr" -To "equipe.microsoft@societe.fr","m.jouan@societe.fr" -Subject "Indicateur WSUS - Fichier Excel complété - $startTime" -SmtpServer "mail.masociete.fr" -Encoding $encoding -bodyashtml

Avec cette méthode, les indicateurs WSUS mensuel sont automatiquement complétés dans le fichier Excel.

Voyons maintenant comment approuver ces kb récupérées juste avant part la synchronisation du Tuesday Patch! Celle du 2ème mardi du mois.

# on récupère les info du serveur, le script s'exécutant localement, pas besoin de préciser le nom, le port, si ssl.
$wsus = Get-WsusServer
# on récupère la date du jour
$startTime = (get-date -f MM-dd-yyyy)
# A laquelle on va retirer environ 25 jours, l'idée étant de ratisser large, c'est à dire récupérer l'ensemble des patch des différentes synchro entre ce Tuesday Patch et celui du mois précédent.
$startTime2 = (get-date).AddDays(-25).ToString("MM-dd-yyyy")

# dans la variable $update on récupère toutes les mises à jour de sécurité de tous les produits datant au maximum de plus de 25j, nous excluons également certaines KB via l'option "$_.Title -notlike"
$update = $wsus.GetUpdates() | where {((($_.UpdateClassificationTitle -like "Mises à jour de définitions") -and ($_.ProductTitles -like "windows defender")) -or (($_.UpdateClassificationTitle -like "Mise à jour de la sécurité") -and ($_.ProductTitles -like "*"))) -and ($_.CreationDate -gt $startTime2) -and ($_.IsDeclined -ne "True") -and (($_.Title -notlike "*4056892*") -and ($_.Title -notlike "*4056891*"))}

# Petit rappel des différents types de mises à jour possibles
# Applications
# Ensemble de mises à jour
# Feature Pack
# Jeux de pilotes
# Mise à jour critique
# Mise à jour de la sécurité
# Mise à jour
# Mises à jour de définitions
# Outil
# Pilote
# Service Pack
# Upgrades
# On récupère l'identifiant des groupes que l'on souhaite traiter "Serveurs PREPROD" et "Serveurs Recette"
$group = $wsus.GetComputerTargetGroups() | where {($_.Name -like '*Serveurs PREPROD*' -or $_.Name -like '*Serveurs Recette*')}

# On approuve maintenant pour cette liste de groupe l'installation de toutes les KB récupérées précédemment via $update
foreach ($Member in $group) {
foreach ($Approval in $update) {
  $Approval[0].Approve(“Install”,$Member)}
   }

# Déclaration de deux chemins au format .csv qui viendront accueillir la liste des serveurs membres des groupes pour l'un et la liste des KB pour l'autre.
$file1 = "\\Fileshare\WSUS-Preprod-Recette-$startTime.csv"
$file2 = "\\FileShare\WSUSKB-Preprod-Recette-$startTime.csv"

# On pousse dans $file1 les serveurs impactés, on oublie pas IncludeDownstreamComputerTargets = $true, ca ne pourra jamais vous desservir
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;
$computerScope.IncludeDownstreamComputerTargets = $true
# On sélectionne le FullDomainName la date de dernière synchro WSUS LastReportedStatusTime et l'appartenance à son groupe RequestedTargetGroupName
$wsus.GetComputerTargets($computerScope) | Where-Object {($_.RequestedTargetGroupName -like "*Serveur PREPROD*" -or $_.RequestedTargetGroupName -like '*Serveurs Recette*')} | select FullDomainName,LastReportedStatusTime,RequestedTargetGroupName | Sort-Object -Property RequestedTargetGroupName | Export-Csv -Path $file1 -Delimiter ";" -append


# On export ensuite la liste des KB approuvées dans $file2
$update | select Title,UpdateClassificationTitle,ProductTitles,LegacyName,CreationDate,ArrivalDate | Out-File $file2 -append -Width 300

# On peut maintenant préparer le mail à envoyer, on déclare un fichier HTM comme vu précédemment, celui est en revanche simplement statique.
$file3 = "C:\Scripts\HTM\ApprobationQual\WSUS.htm"

# On déclare ce fichier HTM en tant que Body du mail
$body = Get-Content -Path $file3 | Out-String

# On modifie l'encoding afin de gérer correctement les accents
$encoding=[System.Text.Encoding]::UTF8

# Puis envoi du mail avec les deux pièces jointes
Send-MailMessage -From "wsus@ma-societe.fr" -To "equipe.microsoft@ma-societe.fr" -Subject "WSUS - Mise à jour Microsoft sur environnement PRE PROD ET Recette - fait le $startTime" -SmtpServer "mail.ma-societe.fr" -Encoding $encoding -Body $body -bodyashtml -Attachments "$file1","$file2"

Le résultat de tout ceci ressemblant à cela:

A travers ces quelques explications et lignes de scripts, je vous invite fortement à utiliser powershell pour préparer\gérer vos serveurs WSUS.
Alors oui, cela nous a pris du temps pour peaufiner tout ca mais le résultat est plus que convainquant aujourd’hui.

Je réaliserai un nouvel article sur WSUS mais cette fois autour du reporting, cela vous permettra de savoir quels serveurs:
– est en attente de redémarrage
– est en erreur suite à l’installation de mise à jours
– n’a pas contacté son serveur WSUS depuis plusieurs jours

Mise à jour -> Wsus – Reporting des clients

A+

Maxime

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s

Créez un site Web ou un blog gratuitement sur WordPress.com.

Retour en haut ↑

Technopreneurph

Technology Entrepreneurship For the World

Chemist Blogger

All things science, technology, and geek culture

Cambly Blog

Practice English with a Native Speaker

BirdsBeep is a Multiplatform Chat Application

BirdsBeep is the uprising of new chatting features that will satisfy.

Deepak verma

Get Latest updates from Famous Tech Blogs in One Blog.

Le mur d'Adrien

De l'administration système pour tous

%d blogueurs aiment cette page :