Diagnostic complet du statut Windows Update (WU, WSUS, SCCM/MECM).
Description
Détection automatique de la source de patching (WU, WSUS, SCCM)
Historique des mises à jour installées
Liste des mises à jour en attente
Vérification de la connectivité WSUS
Diagnostic des erreurs courantes
Support multi-serveurs
Export JSON pour CMDB/automation
Prérequis
Système : Windows Server 2016+ ou Windows 10/11
PowerShell : Version 5.1 minimum
Permissions : Droits administrateur pour interroger Windows Update
Modules : Aucun module externe requis (utilise COM Windows Update)
Cas d'Usage
Diagnostic patching : Identifier pourquoi les mises à jour ne s'installent pas
Audit pré-patch : Vérifier l'état avant une fenêtre de maintenance
Monitoring : Surveiller l'état de patching de l'infrastructure
CMDB Integration : Exporter les données vers un système d'inventaire
Utilisation
# Diagnostic local complet.\Get-WindowsUpdateStatus.ps1# Vérifier plusieurs serveurs.\Get-WindowsUpdateStatus.ps1-ComputerName"SRV01","SRV02"-Credential(Get-Credential)# Afficher l'historique des 30 derniers jours.\Get-WindowsUpdateStatus.ps1-HistoryDays30# Export JSON pour CMDB.\Get-WindowsUpdateStatus.ps1-OutputFormatJSON|Out-Filestatus.json# Vérifier uniquement les updates en attente.\Get-WindowsUpdateStatus.ps1-PendingOnly
Paramètres
Paramètre
Type
Défaut
Description
-ComputerName
String[]
localhost
Serveurs à analyser
-Credential
PSCredential
-
Credentials pour accès distant
-HistoryDays
Int
7
Historique en jours
-PendingOnly
Switch
-
Afficher uniquement les updates en attente
-OutputFormat
String
Table
Format (Table, JSON, CSV)
-IncludeDrivers
Switch
-
Inclure les drivers dans l'analyse
Code Source
#Requires -Version 5.1<#.SYNOPSIS Comprehensive Windows Update status diagnostic..DESCRIPTION Analyzes Windows Update configuration, identifies update source (WU/WSUS/SCCM), lists pending and installed updates, and diagnoses common issues..PARAMETER ComputerName Target computers to analyze..PARAMETER Credential Credentials for remote access..PARAMETER HistoryDays Number of days of update history to retrieve..PARAMETER PendingOnly Only show pending updates..PARAMETER OutputFormat Output format: Table, JSON, or CSV..PARAMETER IncludeDrivers Include driver updates in the analysis..EXAMPLE .\Get-WindowsUpdateStatus.ps1 -ComputerName "SRV01" -HistoryDays 30 Get update status with 30 days of history..NOTES Author: ShellBook Version: 1.0 Date: 2024-01-01#>[CmdletBinding()]param([Parameter(Position=0,ValueFromPipeline=$true)][string[]]$ComputerName=$env:COMPUTERNAME,[Parameter()][System.Management.Automation.PSCredential]$Credential,[Parameter()][ValidateRange(1,365)][int]$HistoryDays=7,[Parameter()][switch]$PendingOnly,[Parameter()][ValidateSet('Table','JSON','CSV')][string]$OutputFormat='Table',[Parameter()][switch]$IncludeDrivers)#region Configuration$ErrorActionPreference='Stop'Set-StrictMode-VersionLatest#endregion#region FunctionsfunctionWrite-Status{param([string]$Message,[ValidateSet('Info','OK','Warning','Error','Header')][string]$Level='Info')$styles=@{'Info'=@{Color='Cyan';Prefix='[*]'}'OK'=@{Color='Green';Prefix='[+]'}'Warning'=@{Color='Yellow';Prefix='[!]'}'Error'=@{Color='Red';Prefix='[X]'}'Header'=@{Color='Magenta';Prefix='==='}}Write-Host"$($styles[$Level].Prefix) $Message"-ForegroundColor$styles[$Level].Color}functionGet-UpdateSourceInfo{<#.SYNOPSIS Detect update source configuration (WU/WSUS/SCCM). #>$source=[PSCustomObject]@{Type ="Windows Update"WSUSServer=$nullWSUSPort=$nullWSUSConnectivity=$nullSCCMManaged=$falseSCCMServer=$nullGroupPolicy=$nullAutoUpdate=$nullLastCheck=$nullErrors=@()}try{# Check WSUS configuration$wuKey='HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'if(Test-Path$wuKey){$wuSettings=Get-ItemProperty-Path$wuKey-ErrorActionSilentlyContinueif($wuSettings.WUServer){$source.Type ="WSUS"$source.WSUSServer=$wuSettings.WUServer$source.GroupPolicy=$true# Parse WSUS URLif($wuSettings.WUServer-match'https?://([^:/]+):?(\d+)?'){$wsusHost=$Matches[1]$wsusPort=if($Matches[2]){[int]$Matches[2]}else{8530}$source.WSUSPort=$wsusPort# Test WSUS connectivitytry{$tcp=[System.Net.Sockets.TcpClient]::new()$tcp.Connect($wsusHost,$wsusPort)$source.WSUSConnectivity=$tcp.Connected$tcp.Close()}catch{$source.WSUSConnectivity=$false$source.Errors+="Cannot connect to WSUS: $wsusHost`:$wsusPort"}}}}# Check SCCM/MECM clienttry{$ccmClient=Get-CimInstance-Namespace'root\ccm'-ClassName'SMS_Client'-ErrorActionStop$source.SCCMManaged=$true$source.Type ="SCCM/MECM"# Get MP server$mpInfo=Get-CimInstance-Namespace'root\ccm'-ClassName'SMS_Authority'-ErrorActionSilentlyContinueif($mpInfo){$source.SCCMServer=$mpInfo.CurrentManagementPoint}}catch{# SCCM not installed}# Get Auto Update settings$auKey='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update'if(Test-Path$auKey){$auSettings=Get-ItemProperty-Path$auKey-ErrorActionSilentlyContinue$source.LastCheck=$auSettings.LastOnlineScanTimeForAppCategory}# Get scheduled task info for AU$auTask=Get-ScheduledTask-TaskName'Scheduled Start'-TaskPath'\Microsoft\Windows\WindowsUpdate\'-ErrorActionSilentlyContinueif($auTask){$source.AutoUpdate=$auTask.State}}catch{$source.Errors+=$_.Exception.Message}return$source}functionGet-PendingUpdates{<#.SYNOPSIS Get list of pending Windows Updates. #>param([bool]$IncludeDriverUpdates)$updates=@()try{# Use COM object for update search$updateSession=New-Object-ComObjectMicrosoft.Update.Session$updateSearcher=$updateSession.CreateUpdateSearcher()# Build search criteria$criteria="IsInstalled=0 and IsHidden=0"if(-not$IncludeDriverUpdates){$criteria+=" and Type='Software'"}$searchResult=$updateSearcher.Search($criteria)foreach($updatein$searchResult.Updates){$updates+=[PSCustomObject]@{Title=$update.TitleKB=($update.KBArticleIDs|Select-Object-First1)Category=($update.Categories|Select-Object-First1-ExpandPropertyName)Severity=$update.MsrcSeveritySize=[Math]::Round($update.MaxDownloadSize/1MB,2)IsDownloaded=$update.IsDownloadedIsMandatory=$update.IsMandatoryRebootRequired=$update.RebootRequiredPublished=$update.LastDeploymentChangeTime}}}catch{Write-Status"Error getting pending updates: $_"-LevelError}return$updates}functionGet-UpdateHistory{<#.SYNOPSIS Get Windows Update installation history. #>param([int]$Days)$history=@()$cutoffDate=(Get-Date).AddDays(-$Days)try{$updateSession=New-Object-ComObjectMicrosoft.Update.Session$updateSearcher=$updateSession.CreateUpdateSearcher()$historyCount=$updateSearcher.GetTotalHistoryCount()if($historyCount-gt0){$updateHistory=$updateSearcher.QueryHistory(0,$historyCount)foreach($entryin$updateHistory){if($entry.Date-lt$cutoffDate){continue}$resultCode=switch($entry.ResultCode){0{"Not Started"}1{"In Progress"}2{"Succeeded"}3{"Succeeded With Errors"}4{"Failed"}5{"Aborted"}default{"Unknown"}}$history+=[PSCustomObject]@{Date=$entry.DateTitle=$entry.TitleKB=if($entry.Title-match'KB(\d+)'){$Matches[1]}else{$null}Result=$resultCodeOperation=switch($entry.Operation){1{"Install"};2{"Uninstall"};default{"Other"}}HResult=if($entry.ResultCode-eq4){"0x{0:X8}"-f$entry.HResult}else{$null}}}}}catch{Write-Status"Error getting update history: $_"-LevelError}return$history|Sort-ObjectDate-Descending}functionGet-ServiceStatus{<#.SYNOPSIS Check Windows Update related services. #>$services=@(@{Name='wuauserv';DisplayName='Windows Update'},@{Name='BITS';DisplayName='Background Intelligent Transfer'},@{Name='CryptSvc';DisplayName='Cryptographic Services'},@{Name='TrustedInstaller';DisplayName='Windows Modules Installer'})$results=foreach($svcin$services){$service=Get-Service-Name$svc.Name-ErrorActionSilentlyContinue[PSCustomObject]@{Name=$svc.NameDisplayName=$svc.DisplayNameStatus=if($service){$service.Status.ToString()}else{"Not Found"}StartType=if($service){$service.StartType.ToString()}else{"N/A"}}}return$results}functionGet-ComponentStoreHealth{<#.SYNOPSIS Check component store (SxS) health. #>$health=[PSCustomObject]@{LastAnalyzeTime=$nullComponentCleanup=$nullRepairPending=$falseWinSxSSize=$null}try{# Check for pending repairs$cbsKey='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing'if(Test-Path"$cbsKey\RebootPending"){$health.RepairPending=$true}# Get WinSxS size$sxsPath="$env:SystemRoot\WinSxS"if(Test-Path$sxsPath){$size=(Get-ChildItem-Path$sxsPath-Recurse-Force-ErrorActionSilentlyContinue|Measure-Object-PropertyLength-Sum).Sum$health.WinSxSSize=[Math]::Round($size/1GB,2)}# Get last cleanup info$cleanupKey='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup'if(Test-Path$cleanupKey){$cleanup=Get-ItemProperty-Path$cleanupKey-ErrorActionSilentlyContinue$health.ComponentCleanup=$cleanup.StateFlags}}catch{# Ignore errors}return$health}functionTest-LocalComputer{<#.SYNOPSIS Run all diagnostics on local computer. #>$result=[PSCustomObject]@{ComputerName=$env:COMPUTERNAMEOSVersion=(Get-CimInstanceWin32_OperatingSystem).CaptionOSBuild=(Get-ItemProperty'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').CurrentBuildLastBootTime=(Get-CimInstanceWin32_OperatingSystem).LastBootUpTimeUpdateSource=$nullServices=@()PendingUpdates=@()RecentHistory=@()ComponentHealth=$nullErrors=@()CheckTime=Get-Date}Write-Status"Analyzing: $($result.ComputerName)"-LevelHeader# Update sourceWrite-Status"Checking update source configuration..."-LevelInfo$result.UpdateSource=Get-UpdateSourceInfo# ServicesWrite-Status"Checking related services..."-LevelInfo$result.Services=Get-ServiceStatus# Pending updatesif(-not$PendingOnly-or$true){Write-Status"Scanning for pending updates..."-LevelInfo$result.PendingUpdates=Get-PendingUpdates-IncludeDriverUpdates$IncludeDrivers}# Historyif(-not$PendingOnly){Write-Status"Retrieving update history ($HistoryDays days)..."-LevelInfo$result.RecentHistory=Get-UpdateHistory-Days$HistoryDays}# Component healthWrite-Status"Checking component store health..."-LevelInfo$result.ComponentHealth=Get-ComponentStoreHealthreturn$result}#endregion#region Maintry{Write-Status"Windows Update Status Diagnostic"-LevelHeaderWrite-Host""$allResults=@()foreach($computerin$ComputerName){if($computer-eq$env:COMPUTERNAME-or$computer-eq'localhost'){$result=Test-LocalComputer}else{# Remote execution via Invoke-Command would go hereWrite-Status"Remote diagnostics for $computer - use PSRemoting"-LevelWarningcontinue}$allResults+=$result}# OutputWrite-Host""Write-Status"Results"-LevelHeaderWrite-Host""foreach($resultin$allResults){# SummaryWrite-Host"Computer: $($result.ComputerName)"-ForegroundColorCyanWrite-Host" OS: $($result.OSVersion) (Build $($result.OSBuild))"Write-Host" Update Source: $($result.UpdateSource.Type)"if($result.UpdateSource.WSUSServer){$wsusStatus=if($result.UpdateSource.WSUSConnectivity){"Connected"}else{"UNREACHABLE"}Write-Host" WSUS Server: $($result.UpdateSource.WSUSServer) [$wsusStatus]"}if($result.UpdateSource.SCCMManaged){Write-Host" SCCM Server: $($result.UpdateSource.SCCMServer)"}Write-Host""# ServicesWrite-Host" Services:"-ForegroundColorYellowforeach($svcin$result.Services){$color=if($svc.Status-eq'Running'){'Green'}else{'Red'}Write-Host" $($svc.DisplayName): "-NoNewlineWrite-Host$svc.Status-ForegroundColor$color}Write-Host""# Pending updatesWrite-Host" Pending Updates: $($result.PendingUpdates.Count)"-ForegroundColorYellowif($result.PendingUpdates.Count-gt0){$critical=($result.PendingUpdates|Where-Object{$_.Severity-eq'Critical'}).Count$important=($result.PendingUpdates|Where-Object{$_.Severity-eq'Important'}).CountWrite-Host" Critical: $critical | Important: $important"foreach($updatein$result.PendingUpdates|Select-Object-First10){$kb=if($update.KB){"KB$($update.KB)"}else{""}Write-Host" - [$($update.Severity)] $kb $($update.Title.Substring(0,[Math]::Min(60,$update.Title.Length)))..."}if($result.PendingUpdates.Count-gt10){Write-Host" ... and $($result.PendingUpdates.Count-10) more"}}Write-Host""# Recent failures$failures=$result.RecentHistory|Where-Object{$_.Result-eq'Failed'}|Select-Object-First5if($failures){Write-Host" Recent Failures:"-ForegroundColorRedforeach($failin$failures){Write-Host" - $($fail.Date.ToString('yyyy-MM-dd')): $($fail.Title.Substring(0,[Math]::Min(50,$fail.Title.Length)))... [$($fail.HResult)]"}Write-Host""}# Component healthWrite-Host" Component Store: $($result.ComponentHealth.WinSxSSize) GB"-ForegroundColorYellowif($result.ComponentHealth.RepairPending){Write-Host" WARNING: Repair pending"-ForegroundColorRed}Write-Host""}# JSON outputif($OutputFormat-eq'JSON'){$allResults|ConvertTo-Json-Depth10}}catch{Write-Status"Fatal error: $_"-LevelErrorexit1}#endregion