Comment automatiser l’installation avec WSUS, GPO et PowerShell ?

mise à jour des patch

Comment automatiser quand on a uniquement WSUS ?

Voici un cas concret de configuration d’un environnement Microsoft possible :

Vous avez une GPO qui interdit d’installer et de redémarrer vos serveurs (ou postes de travail) automatiquement. Cela afin de maîtriser le redémarrage et de surveiller les services applicatifs, traitements en cours etc.

Vous avez

Du coup vous devez lancer l’installation manuellement. Il n’y a pas de demi mesure. A moins d’opter pour un système plus complet tels que SCCM, Altiris ou autre.

 

update mise à jour horloge

Fonctionnement des commandes Windows Update

Voici les principales commandes :

  • CreateupdateSearcher()
  • CreateUpdateDownloader()

Mais ses commandes ne se lancent que localement, à distance cela ne fonctionne ni en Ps-Session, Invoke-command. Il faut un compte système local pour lancer la commande.

nuage de mot cyber security

Solution de patching avec WSUS, GPO et PowerShell

Voici une solution pour lancer l’installation des patchs quand vous voulez et à distance, de façon entièrement automatisé:

Faire un script avec les commandes Windows Update qui sera lancé localement. Plusieurs façon de le faire donc, ci dessous une des façons de faire, pas forcément la meilleure, cela sera perfectionné et je vous ferai un update de l’article ;-).

Le principe utilisé ci-dessous est de copier le script localement avec un Invoke-Commend (PowerShell) puis de créer une tache planifiée qui lancera le script avec un compte système local.

1. Copie du script en local

 

$ListeServeur = Get-Content "C:\Temp\WSUS\ListeServeurs.csv"
foreach($Serveur in $ListeServeur){
Invoke-Command -ComputerName $Serveur -ScriptBlock {copy-item -Path "C:\temp\WSUS\PatchManagement.ps1" -Destination "\\$Serveur\c$\Temp\PatchManagement.ps1"}
}

 

2. Création d’une tache planifiée pour exécuter le script

 

$ListeServeur = Get-Content "C:\Temp\WSUS\ListeServeurs.csv"
foreach($Serveur in $ListeServeur){
# Lancement à distance, pour un lancement local sur le serveur, copier simplement les variables entre les { }
Invoke-Command -ComputerName $Serveur -ScriptBlock
{
$TacheGeneralNom = "Patch Management - Wsus"
$TacheGeneralDescription = "WSUS"
$TacheActionProgramme = "powershell.exe"
$TacheActionCheminArg = "C:\temp\PatchManagement.ps1"
$TacheActionArguments = "-Executionpolicy Bypass -file $TacheActionCheminArg"

$ServiceObjet = New-Object -ComObject("Schedule.Service")
$ServiceObjet.Connect()

$TacheChemin = $ServiceObjet.GetFolder("\")

$TacheDefinition = $ServiceObjet.NewTask(0) # Doit-Être à 0
$TacheDefinition.RegistrationInfo.Description = "$TacheGeneralDescription"
$TacheDefinition.Settings.Enabled = $True
$TacheDefinition.Principal.RunLevel = 1
$Triggers = $TacheDefinition.Triggers
#$Trigger = $Triggers.Create(8)
$Action = $TacheDefinition.Actions.Create(0)
$Action.Path = $TacheActionProgramme
$Action.Arguments = $TacheActionArguments
$TacheChemin.RegisterTaskDefinition($TacheGeneralNom,$TacheDefinition,6,"System",$null,5)
}}

cable serveurs en datacenter, cloud, wan

3. Lancement de la tache planifiée avec gestion des erreurs

 

$ListeServeur = Get-Content « C:\Temp\WSUS\ListeServeurs.csv »

foreach($Serveur in $ListeServeur){
Invoke-Command -ComputerName $Serveur -ScriptBlock {
$Error.Clear()

4 – Lancement de la tâche planifiée

schtasks /Run /tn « Patch Management – Wsus »
if($Error){
« $Serveur;NOK » >> « C:\temp\WSUS\Erreur.csv »
}
else{
« $Serveur;OK » >> « C:\temp\WSUS\Erreur.csv »
}}}

Microsoft Windows Powershell

5 – Si vous voulez supprimer la tache planifiée à la fin de l’opération

$ListeServeur = Get-Content "C:\Temp\WSUS\ListeServeurs.csv"

foreach($Serveur in $ListeServeur){
    Invoke-Command -ComputerName $Serveur -ScriptBlock {
        # Suppression de la tâche planifiée "Patch Management - Wsus" en forcé
        schtasks /delete /tn "Patch Management - Wsus" /f
    }}

6 – Script de vérification des KBs sur WSUS puis d’installation et de reboot.

pansemant, patch, sécurité

Penser à modifier les noms des adresses mails et du serveurs SMTP pour la réception des notifications de chaque serveurs

 

Function WSUSProcess{

$EmailReport = $true
$FileReport = $true
$To = "EMAIL A MODIFIER","SECOND EMAIL"
$From = $env:COMPUTERNAME + "@NOM DE DOMAINE"
$SMTPServer = "NOM DU SERVEUR MAILS"
$FileReportPath = "C:\TEMP\"
$AutoRestart = $true
$AutoRestartIfPending = $true

$Path = $FileReportPath + "$env:ComputerName" + "_" + (Get-Date -Format dd-MM-yyyy_HH-mm).ToString() + ".html"

#Testing if there are any pending reboots from earlier Windows Update sessions 
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"){
#Report to e-mail if enabled 
if ($EmailReport -eq $true){ 
$pendingboot = @{$false="was pending for a restart from an earlier Windows Update session. Due to the reboot preferences in the script, a reboot was not initiated."; $true="was restarted due to a pending restart from an earlier Windows Update session."} 
$status = $pendingboot[$AutoRestartIfPending] 
$messageParameters = @{
Subject = "Windows Update report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())"
Body = "Invoke-WindowsUpdate was run on $env:ComputerName, and the server $status `nPlease run Invoke-WindowsUpdate again when the server is rebooted."
from = $From
To = $To
SmtpServer = $SMTPServer
} 
Send-MailMessage @messageParameters -BodyAsHtml 

#Report to file if enabled 
if ($FileReport -eq $true){ 
"Invoke-WindowsUpdate was run on $env:ComputerName, and the server $status `nPlease run Invoke-WindowsUpdate again when the server is rebooted." | Out-File -FilePath $path 
}

#Reboot if autorestart for pending updates is enabled
if ($AutoRestartIfPending)
{ shutdown.exe /t 0 /r }
}
exit 
}

#Checking for available updates
$updateSession = new-object -com "Microsoft.Update.Session"

write-progress -Activity "Updating" -Status "Checking available updates"

$criteria="IsInstalled=0 and Type='Software'"

$updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates

$downloader = $updateSession.CreateUpdateDownloader()

$downloader.Updates = $Updates


#If no updates available, do nothing 
if ($downloader.Updates.Count -eq "0") { 

#Report to e-mail if enabled 
if ($EmailReport -eq $true){
$messageParameters = @{ 
Subject = "Windows Update report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())" 
Body = "Invoke-WindowsUpdate was run on $env:ComputerName, but no new updates were found. Please try again later." 
from = $From 
To = $To 
SmtpServer = $SMTPServer 
} 
Send-MailMessage @messageParameters -BodyAsHtml 
} 

#Report to file if enabled 
if ($FileReport -eq $true){ 
"Invoke-WindowsUpdate was run on $env:ComputerName, but no new updates were found. Please try again later." | Out-File -FilePath $Path 
}} 
else { 
#If updates are available, download and install 
write-progress -Activity 'Updating' -Status "Downloading $($downloader.Updates.count) updates" 

$resultcode= @{0="Not Started"; 1="In Progress"; 2="Succeeded"; 3="Succeeded With Errors"; 4="Failed" ; 5="Aborted" } 
$Result= $downloader.Download()

if(($Result.Hresult -eq 0) –and (($result.resultCode –eq 2) -or ($result.resultCode –eq 3)) ){ 
$updatesToInstall = New-object -com "Microsoft.Update.UpdateColl" 
$Updates | where {$_.isdownloaded} | foreach-Object {$updatesToInstall.Add($_) | out-null} 

$installer = $updateSession.CreateUpdateInstaller() 
$installer.Updates = $updatesToInstall 

write-progress -Activity 'Updating' -Status "Installing $($Installer.Updates.count) updates" 

$installationResult = $installer.Install()
$Global:counter=-1

$Report = $installer.updates | 
Select-Object -property Title,EulaAccepted,@{Name='Result';expression={$ResultCode[$installationResult.GetUpdateResult($Global:Counter++).resultCode ] }},@{Name='Reboot required';expression={$installationResult.GetUpdateResult($Global:Counter++).RebootRequired }} | 
ConvertTo-Html 

#Report to e-mail if enabled 
if ($EmailReport -eq $true){
$messageParameters = @{ 
Subject = "Windows Update report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())" 
Body = $Report | Out-String 
from = $From 
To = $To 
SmtpServer = $SMTPServer 
} 
Send-MailMessage @messageParameters -BodyAsHtml 
} 

#Report to file if enabled 
if ($FileReport -eq $true){
$Report | Out-File -FilePath $path 
} 

#Reboot if autorestart is enabled and one or more updates are requiring a reboot 
if ($autoRestart -and $installationResult.rebootRequired)
{ shutdown.exe /t 0 /r } 
} }}

WSUSProcess






logo IT Consult

Laisser un commentaire