<# .SYNOPSIS Shows which update source a Windows device is actually pointed at, and can reset it. .DESCRIPTION Reads the Windows Update policy keys (WSUS server, scan source, WUfB deferrals, the Intune/MDM policy store) plus the Windows Update Agent's default service, and makes a best guess at where the device gets its updates: WSUS, Windows Update for Business, a mix of the two, or plain unmanaged Windows Update. With -ResetPolicy it backs up and deletes the local WindowsUpdate policy key, then restarts the Windows Update service. Group Policy or ConfigMgr will put back whatever they own at the next refresh, so this is for clearing out leftovers, not for fighting an active policy. .PARAMETER ResetPolicy Back up and remove HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate. Honors -WhatIf. .PARAMETER BackupPath Folder for the .reg backup taken before a reset. .EXAMPLE .\Get-WindowsUpdateSource.ps1 .EXAMPLE .\Get-WindowsUpdateSource.ps1 -ResetPolicy -WhatIf #> [CmdletBinding(SupportsShouldProcess)] param( [switch]$ResetPolicy, [ValidateNotNullOrEmpty()] [string]$BackupPath = (Join-Path $env:ProgramData 'WindowsUpdatePolicyBackup') ) $policyKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' $mdmKey = 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device\Update' function Get-RegValues([string]$Path) { $item = Get-ItemProperty -Path $Path -ErrorAction SilentlyContinue if ($item) { $item } else { [pscustomobject]@{} } } function Get-UpdateSourceReport { $wu = Get-RegValues $policyKey $au = Get-RegValues "$policyKey\AU" $mdm = Get-RegValues $mdmKey # Windows 10 2004 and later: per-class scan source. 1 = WSUS, 0 = Windows Update. $scanSource = [ordered]@{} foreach ($class in 'Feature', 'Quality', 'Driver', 'Other') { $value = $wu."SetPolicyDrivenUpdateSourceFor${class}Updates" $scanSource[$class] = switch ($value) { 1 { 'WSUS' } 0 { 'WindowsUpdate' } default { 'NotSet' } } } $defaultService = $null try { $manager = New-Object -ComObject Microsoft.Update.ServiceManager $defaultService = @($manager.Services) | Where-Object { $_.IsDefaultAUService } | Select-Object -First 1 -ExpandProperty Name } catch { Write-Verbose "Couldn't query the Windows Update Agent: $($_.Exception.Message)" } $usesWsus = ($au.UseWUServer -eq 1) -and [bool]$wu.WUServer $mdmSettings = @($mdm.PSObject.Properties | Where-Object { $_.Name -notlike 'PS*' -and $_.Name -notlike '*_ProviderSet' -and $_.Name -notlike '*_WinningProvider' }) $hasWufb = ($null -ne $wu.DeferQualityUpdatesPeriodInDays) -or ($null -ne $wu.DeferFeatureUpdatesPeriodInDays) -or ($null -ne $wu.TargetReleaseVersionInfo) -or ($mdmSettings.Count -gt 0) $source = if ($usesWsus -and ($scanSource.Values -contains 'WindowsUpdate')) { 'Mixed (WSUS + Windows Update)' } elseif ($usesWsus) { 'WSUS' } elseif ($hasWufb) { 'Windows Update for Business' } else { 'Windows Update (unmanaged)' } $target = (@($wu.ProductVersion, $wu.TargetReleaseVersionInfo) | Where-Object { $_ }) -join ' ' [pscustomobject]@{ ComputerName = $env:COMPUTERNAME LikelySource = $source WUServer = $wu.WUServer WUStatusServer = $wu.WUStatusServer UseWUServer = $au.UseWUServer BlockInternetWU = $wu.DoNotConnectToWindowsUpdateInternetLocations ScanSourceFeature = $scanSource.Feature ScanSourceQuality = $scanSource.Quality ScanSourceDriver = $scanSource.Driver ScanSourceOther = $scanSource.Other DeferQualityDays = $wu.DeferQualityUpdatesPeriodInDays DeferFeatureDays = $wu.DeferFeatureUpdatesPeriodInDays TargetVersion = if ($target) { $target } else { $null } MdmUpdateSettings = $mdmSettings.Count NoAutoUpdate = $au.NoAutoUpdate DefaultAUService = $defaultService ConfigMgrClient = [bool](Get-Service -Name CcmExec -ErrorAction SilentlyContinue) } } $report = Get-UpdateSourceReport if (-not $ResetPolicy) { return $report } if (-not (Get-Item -Path $policyKey -ErrorAction SilentlyContinue)) { Write-Verbose 'No local WindowsUpdate policy key. Nothing to reset.' return $report } if ($report.ConfigMgrClient) { Write-Warning 'This device has a ConfigMgr client. Its software update point will rewrite the WSUS settings at the next policy cycle.' } if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Back up and remove $policyKey, then restart wuauserv")) { try { if (-not (Test-Path -Path $BackupPath)) { New-Item -Path $BackupPath -ItemType Directory -Force | Out-Null } $backupFile = Join-Path $BackupPath ("WindowsUpdate-{0:yyyyMMdd-HHmmss}.reg" -f (Get-Date)) & reg.exe export 'HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' $backupFile /y | Out-Null if ($LASTEXITCODE -ne 0) { throw "reg export failed with exit code $LASTEXITCODE. Not removing anything." } Write-Verbose "Backed up policy to $backupFile" Remove-Item -Path $policyKey -Recurse -Force -ErrorAction Stop Restart-Service -Name wuauserv -Force -ErrorAction Stop Write-Verbose 'Policy key removed and Windows Update service restarted.' } catch { Write-Error "Reset failed: $($_.Exception.Message)" exit 1 } Get-UpdateSourceReport } else { $report }