Voici un script qui vous permettra de réaliser un état des lieu sur les mises à jour de sécurité nécessaires pour l'ensemble de vos serveurs rattachés à un WSUS.
Attention : Prenez soins de modifier les variables suivantes :
- Sur la ligne 12 vous pouvez remplacer le "-30" par un valeur plus élevé si vous souhaitez un delta plus large (le -30 correspondant à M - 1, et ainsi connaitre le nombre de mise à jours manquante à J-30 jours)
- Sur la ligne 14 $Alias (doit correspondra à l'alias renseigné dans votre DNS).
- Ligne 44 vous pouvez ajouter un -Credential (si vous n'exécutez pas ce script dans un contexte avec les droits nécessaires).
Ce dernier est une version pour un WSUS unique en mode autonome ou déconnecté, ne possédant pas de Downstram Server, je publierais une autre version pour ce cas de figure.
#################################
# Step 1 : Variables Definition #
#################################
#region - Variables
$RootFolder = "C:\Temp\WSUS"
$ResultFolder = "$RootFolder\Result"
$LogFolder = "$RootFolder\Logs"
$Archives = "$RootFolder\Archives"
$AllFolders = $RootFolder, $ResultFolder, $LogFolder, $Archives
$LogFile = "$LogFolder\GeneralLog.log"
$Date = Get-Date -Format M
$TargetDate = ((Get-Date).AddDays(-30)).ToString('MM/dd/yyyy')
$Array = @()
$Alias = "wsus"
# Folders creation
foreach ($Folder in $AllFolders) {
If (!(Test-Path $Folder)) {
New-Item $Folder -ItemType Directory
}
}
# Old Files deletion
Get-ChildItem $LogFolder | Remove-Item -Force
Get-ChildItem $ResultFolder | Remove-Item -Force
#endregion - Variables
###############################
# Step 2 : Locate WSUS Server #
###############################
#region - Locate WSUS Server
Write-Output "Trying to locate WSUS server" | Add-Content $LogFile
Try {
$WSUSServer = Resolve-DnsName $Alias -ErrorAction Stop | select -ExpandProperty Name -Last 1
Write-Output "Successfully locate WSUS server" | Add-Content $LogFile
}
Catch {
Write-Output "Failed to locate WSUS server" | Add-Content $LogFile
}
# Wsus Role Check
Write-Output "Verifying WSUS server role installation" | Add-Content $LogFile
Try {
$WsusRoleInstalled = Invoke-Command -ComputerName $WSUSServer -ScriptBlock {Get-WindowsFeature | Where-Object {($_.InstallState -eq "Installed") -and ($_.Name -like "UpdateServices")}} -ErrorAction Stop | Select-Object -Property Installed
Write-Output "Successfully Run the query" | Add-Content $LogFile
If ($WsusRoleInstalled.Installed -ne $true) {
# End of Script
Write-Output "WSUS Server not found" | Add-Content $LogFile
Exit
}
}
Catch {
Write-Output "Failed to verify WSUS server role installation" | Add-Content $LogFile
Exit
}
#endregion - Locate WSUS Server
############################
# Step 3 : WSUS Connection #
############################
#region - WSUS Connection
# Try on default port 8530
Try {
$WsusPort = "8530"
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)
$Connection = $Wsus.Name
}
Catch {
# Try on port 80
Try {
$WsusPort = "80"
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)
$Connection = $Wsus.Name
}
Catch {
# Try on port 8531
Try {
$WsusPort = "8531"
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$true,$WsusPort)
$Connection = $Wsus.Name
}
Catch {
# Try on port 443
Try {
$WsusPort = "443"
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$true,$WsusPort)
$Connection = $Wsus.Name
}
Catch {
# End of Script
Write-Output "WSUS Server connection failed on all ports" | Add-Content $LogFile
Exit
}
}
}
}
#endregion - WSUS Connection
###########################
# Step 4 : WSUS Reporting #
###########################
#region - WSUS Reporting
# Variables Definition
$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updateClassifications = $Wsus.GetUpdateClassifications() | Where-Object {$_.Title -eq "Security Updates"}
$UpdateScope.Classifications.AddRange($updateClassifications)
$Servers = $wsus.GetComputerTargets($computerscope) | Where-Object {($_.ComputerRole -eq "Server")}
$NBServers = $Servers.Count
Write-Output "WSUS Server has $NBServers to manage" | Add-Content $LogFile
$Servers | Foreach {
$FullDomainName = $_.FullDomainName
$WorkstationID = $_.Id
$LastSyncClient = $_.LastSyncTime
[STRING]$LastSyncResultClient = $_.LastSyncResult
$LastReportedStatusTime = $_.LastReportedStatusTime
$IPAddress = ($_.IPAddress).IPAddressToString
$Id = $_.Id
$Make = $_.Make
$Model = $_.Model
$OSLanguage = ($_.OSInfo).DefaultUILanguage
$OSArchitecture = $_.OSArchitecture
$OSFamily = $_.OSFamily
$OSDescription = $_.OSDescription
$ComputerTargetGroupIds = $_.ComputerTargetGroupIds
$SyncsFromDownstreamServer = $_.SyncsFromDownstreamServer
$UpdateServer = $_.UpdateServer.Name
# Get AD Information
Try {
Write-Output "Trying to retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
$CurrentServer = Get-ADComputer -Filter {DNSHostName -eq $FullDomainName} -Properties CanonicalName -ErrorAction Stop | Select-Object Enabled,CanonicalName,OperatingSystem,Name
Write-Output "Successfully retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
}
Catch {
Write-Output "Failed to retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
}
# Define state for Begining and End of year, plus a targeted date (here M-30)
$updatescope.ToCreationDate=[DATETIME]"01/31/2022"
$KBToInstallJanuary = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
$updatescope.ToCreationDate=[DATETIME]"12/31/9999"
$KBToInstallUpToDate = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
$updatescope.ToCreationDate=[DATETIME]"$TargetDate"
$KBToInstallJ30 = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
$IPAddress = ($_."IPAddress").IPAddressToString
$Array += New-Object psobject -Property @{
FullDomainName = $FullDomainName
WorkstationID = $Id
LastSyncClient = $LastSyncClient
LastSyncResultClient = $LastSyncResultClient
LastReportedStatusTime = $LastReportedStatusTime
IPAddress = $IPAddress
Enabled = $CurrentServer.Enabled
CanonicalName =$CurrentServer.CanonicalName
Name = $CurrentServer.Name
KBNeededInJanuary = $KBToInstallJanuary
KBNeededLastMonth = $KBToInstallJ30
KBNeededToBeUpToDate = $KBToInstallUpToDate
Id = $Id
Make = $Make
Model = $Model
OSLanguage = $OSLanguage
OSArchitecture = $OSArchitecture
OSFamily = $OSFamily
OSDescription = $OSDescription
ComputerTargetGroupIds = $ComputerTargetGroupIds
SyncsFromDownstreamServer = $SyncsFromDownstreamServer
UpdateServer = $UpdateServer
}
# Release
$FullDomainName = $null
$WorkstationID = $null
$LastSyncClient = $null
$LastSyncResultClient = $null
$LastReportedStatusTime = $null
$IPAddress = $null
$Id = $null
$Make = $null
$Model = $null
$OSLanguage = $null
$OSArchitecture = $null
$OSFamily = $null
$OSDescription = $null
$ComputerTargetGroupIds = $null
$SyncsFromDownstreamServer = $null
$CurrentServer = $null
$UpdateServer = $null
$KBToInstallJanuary = $null
$KBToInstallUpToDate = $null
$KBToInstallJ30 = $null
}
#endregion - WSUS Reporting
########################
# Step 4 : Export Data #
########################
#region - Export Data
$Array | select WorkstationID,Make,Model,OSFamily,OSDescription,OSArchitecture,OSLanguage,IPAddress,FullDomainName,Name,CanonicalName,Enabled,SyncsFromDownstreamServer,UpdateServer,LastReportedStatusTime,LastSyncClient,LastSyncResultClient,KBNeededInJanuary,KBNeededLastMonth,KBNeededToBeUpToDate | Export-Csv $ResultFolder\Report.csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation
#endregion - Export Data