# Prints whether the guest is upgrading or downloading updates. # Read-only. Run as Administrator for complete results (BITS jobs of all users, # command lines of system processes); a standard user gets partial output. param( [int]$EventCount = 8 ) $ErrorActionPreference = 'Continue' $ProgressPreference = 'SilentlyContinue' function Write-Section([string]$Title) { Write-Host '' Write-Host "== $Title ==" } function Out-Text($Value) { $text = ($Value | Out-String).TrimEnd() if ($text) { Write-Host $text } else { Write-Host '(none)' } } $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $isAdmin = [Security.Principal.WindowsPrincipal]::new($identity).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator) Write-Section 'Host' Write-Host ('Time: {0}' -f (Get-Date)) Write-Host ('Admin: {0}' -f $isAdmin) if (-not $isAdmin) { Write-Host 'Warning: not elevated, BITS jobs and process command lines may be incomplete.' } Write-Section 'Operating system' Out-Text (Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber, LastBootUpTime | Format-List) Write-Section 'Update policy' $wuPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' $props = 'NoAutoUpdate', 'NoAutoRebootWithLoggedOnUsers', 'ExcludeWUDriversInQualityUpdate', 'TargetReleaseVersion', 'TargetReleaseVersionInfo' foreach ($item in @(@{ Path = "$wuPath\AU" }, @{ Path = $wuPath })) { $values = Get-ItemProperty -Path $item.Path -ErrorAction SilentlyContinue foreach ($name in $props) { if ($values -and $values.PSObject.Properties[$name]) { Write-Host ('{0,-34} {1}' -f $name, $values.$name) } } } Write-Section 'Upgrade / pending-reboot markers' $markers = [ordered]@{ 'C:\$WINDOWS.~BT (upgrade staging)' = Test-Path -LiteralPath 'C:\$WINDOWS.~BT' 'C:\Windows\WinSxS\pending.xml' = Test-Path -LiteralPath 'C:\Windows\WinSxS\pending.xml' 'WindowsUpdate RebootRequired' = Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' 'Component Based Servicing RebootPending' = Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending' } foreach ($key in $markers.Keys) { Write-Host ('{0,-42} {1}' -f $key, $markers[$key]) } Write-Section 'Update services' Out-Text (Get-Service wuauserv, UsoSvc, TrustedInstaller, bits, WaaSMedicSvc, DoSvc ` -ErrorAction SilentlyContinue | Select-Object Name, Status, StartType | Format-Table -AutoSize) Write-Section 'Update scheduled tasks' Out-Text (Get-ScheduledTask ` -TaskPath '\Microsoft\Windows\UpdateOrchestrator\*', '\Microsoft\Windows\WindowsUpdate\*' ` -ErrorAction SilentlyContinue | Select-Object TaskName, State | Format-Table -AutoSize) Write-Section 'Update-related processes' $pattern = 'setup|TiWorker|TrustedInstaller|UsoClient|MoSetup|SetupHost|SetupPrep|MusNotification|wusa|dism|EdgeUpdate|Installer' Out-Text (Get-CimInstance Win32_Process | Where-Object { $_.Name -match $pattern -or $_.CommandLine -match 'wuauserv|UsoSvc|DoSvc' } | Select-Object ProcessId, Name, CreationDate, CommandLine | Format-List) Write-Section 'BITS download jobs' Out-Text (Get-BitsTransfer -AllUsers -ErrorAction SilentlyContinue | Select-Object DisplayName, JobState, BytesTransferred, BytesTotal | Format-Table -AutoSize) Write-Section "Windows Update events (last $EventCount)" Out-Text (Get-WinEvent -LogName 'Microsoft-Windows-WindowsUpdateClient/Operational' ` -MaxEvents $EventCount -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, Message | Format-List) Write-Section 'Established HTTP/HTTPS connections by process' Out-Text (Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue | Where-Object { $_.RemotePort -in 80, 443 } | Group-Object OwningProcess | ForEach-Object { $process = Get-Process -Id $_.Name -ErrorAction SilentlyContinue [pscustomobject]@{ Pid = $_.Name; Process = $process.Name; Connections = $_.Count } } | Format-Table -AutoSize) Write-Section 'Network receive rate (2 samples, 2 s apart)' $counter = Get-Counter '\Network Interface(*)\Bytes Received/sec' ` -SampleInterval 2 -MaxSamples 2 -ErrorAction SilentlyContinue if ($counter) { Out-Text ($counter[-1].CounterSamples | Select-Object InstanceName, @{ n = 'KBps'; e = { [int]($_.CookedValue / 1024) } } | Format-Table -AutoSize) } else { Write-Host '(performance counters unavailable)' }