diff --git a/SCCM-WU/Fix-WU-SCCM-DualScan.ps1 b/SCCM-WU/Fix-WU-SCCM-DualScan.ps1 index ab79c1a..e9a2697 100644 --- a/SCCM-WU/Fix-WU-SCCM-DualScan.ps1 +++ b/SCCM-WU/Fix-WU-SCCM-DualScan.ps1 @@ -1,112 +1,103 @@ -$ErrorActionPreference = 'Stop' +$ErrorActionPreference = 'SilentlyContinue' -$outDir = 'C:\install\missing_updates' -if (-not (Test-Path $outDir)) { - New-Item -Path $outDir -ItemType Directory -Force | Out-Null -} -$logFile = Join-Path $outDir 'missing_updates.txt' -if (Test-Path $logFile) { Remove-Item $logFile -Force } +Write-Host "[1/8] WU services stoppen..." +Stop-Service wuauserv -Force +Stop-Service bits -Force +Stop-Service cryptsvc -Force -function Log { - param([string]$Text) - Write-Host $Text - Add-Content -Path $logFile -Value $Text +Write-Host "[2/8] WUfB registry waarden verwijderen..." +$wu = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' +$au = "$wu\AU" + +$keys = @( + 'BranchReadinessLevel', + 'DeferFeatureUpdates', + 'DeferFeatureUpdatesPeriodInDays', + 'DeferQualityUpdates', + 'DeferQualityUpdatesPeriodInDays', + 'ManagePreviewBuilds', + 'ManagePreviewBuildsPolicyValue', + 'PauseFeatureUpdates', + 'PauseFeatureUpdatesStartTime', + 'PauseQualityUpdates', + 'PauseQualityUpdatesStartTime', + 'ProductVersion', + 'TargetReleaseVersion', + 'TargetReleaseVersionInfo', + 'DeferUpgrade', + 'DeferUpgradePeriod', + 'DeferUpdatePeriod', + 'ExcludeWUDriversInQualityUpdate' +) +foreach ($k in $keys) { + Write-Host " - $k" + Remove-ItemProperty -Path $wu -Name $k -Force } -Log "Online WU scan (buiten WSUS om) - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Log "Server: $env:COMPUTERNAME" -Log ('=' * 70) - -# --- Online scan tegen Microsoft Update, WSUS negeren --- -Log "" -Log "Scannen tegen Microsoft Update (kan een paar minuten duren)..." -$session = New-Object -ComObject Microsoft.Update.Session -$searcher = $session.CreateUpdateSearcher() -$searcher.ServerSelection = 3 # ssOthers = expliciet niet WSUS -$searcher.ServiceID = '7971f918-a847-4430-9279-4a52d1efe18d' # Microsoft Update - -$result = $searcher.Search("IsInstalled=0 AND Type='Software' AND IsHidden=0") - -$count = $result.Updates.Count -Log "Aantal ontbrekende updates gevonden: $count" -Log ('=' * 70) - -if ($count -eq 0) { - Log "" - Log "Geen ontbrekende updates. Server is up-to-date volgens Microsoft Update." - return +Write-Host "[3/8] OS-specifieke fix bepalen..." +$build = (Get-CimInstance Win32_OperatingSystem).BuildNumber +Write-Host " Build: $build" +if ($build -in 14393, 17763, 20348) { + Write-Host " Server 2016/2019/2022: DisableDualScan = 1 zetten" + New-ItemProperty -Path $wu -Name 'DisableDualScan' -PropertyType DWord -Value 1 -Force | Out-Null } - -# --- Per update: details loggen en download-URL's verzamelen --- -$downloadList = @() - -for ($i = 0; $i -lt $count; $i++) { - $u = $result.Updates.Item($i) - $kb = ($u.KBArticleIDs | ForEach-Object { "KB$_" }) -join ', ' - - Log "" - Log ("-" * 70) - Log "[$($i+1)/$count] $($u.Title)" - Log " KB: $kb" - Log " Ernst: $($u.MsrcSeverity)" - Log " UpdateID: $($u.Identity.UpdateID)" - - # Download-URL's uit de bundle halen (bundelt vaak de echte .msu) - $bundled = $u.BundledUpdates - if ($bundled.Count -eq 0) { - # Geen bundle, probeer update zelf - foreach ($c in $u.DownloadContents) { - if ($c.DownloadUrl) { - Log " URL: $($c.DownloadUrl)" - $downloadList += [PSCustomObject]@{ KB = $kb; Url = $c.DownloadUrl } - } - } - } else { - for ($b = 0; $b -lt $bundled.Count; $b++) { - $bu = $bundled.Item($b) - foreach ($c in $bu.DownloadContents) { - if ($c.DownloadUrl) { - Log " URL: $($c.DownloadUrl)" - $downloadList += [PSCustomObject]@{ KB = $kb; Url = $c.DownloadUrl } - } - } - } +if ($build -eq 26100) { + Write-Host " Server 2025: policy-driven update source waarden zetten" + $srcKeys = @( + 'SetPolicyDrivenUpdateSourceForFeatureUpdates', + 'SetPolicyDrivenUpdateSourceForQualityUpdates', + 'SetPolicyDrivenUpdateSourceForDriverUpdates', + 'SetPolicyDrivenUpdateSourceForOtherUpdates' + ) + foreach ($k in $srcKeys) { + Write-Host " - $k" + New-ItemProperty -Path $wu -Name $k -PropertyType DWord -Value 1 -Force | Out-Null } + if (-not (Test-Path $au)) { + New-Item -Path $au -Force | Out-Null + } + New-ItemProperty -Path $au -Name 'UseUpdateClassPolicySource' -PropertyType DWord -Value 1 -Force | Out-Null } -# --- Download-URL's apart wegschrijven --- -$urlFile = Join-Path $outDir 'download_urls.txt' -$downloadList | ForEach-Object { $_.Url } | Sort-Object -Unique | Set-Content $urlFile -Log "" -Log ('=' * 70) -Log "Alle download-URL's staan in: $urlFile" +Write-Host "[4/8] WU cache leegmaken..." +Remove-Item 'C:\Windows\SoftwareDistribution\DataStore\*' -Recurse -Force +Remove-Item 'C:\Windows\SoftwareDistribution\Download\*' -Recurse -Force -# --- Bestanden downloaden via BITS --- -Log "" -Log "Downloaden naar $outDir ..." -$n = 0 -foreach ($item in ($downloadList | Sort-Object Url -Unique)) { - $n++ - $fileName = Split-Path $item.Url -Leaf - # Zorg dat de bestandsnaam het KB-nummer bevat voor herkenbaarheid - $kbClean = ($item.KB -replace '[, ]', '_') - $dest = Join-Path $outDir "$($kbClean)__$fileName" +Write-Host "[5/8] WU services starten..." +Start-Service cryptsvc +Start-Service bits +Start-Service wuauserv - Log " [$n] $fileName" +Write-Host "[6/8] CcmExec stoppen (max 60 sec)..." +$svc = Get-Service ccmexec +if ($svc.Status -eq 'Running') { + Stop-Service ccmexec -Force try { - Start-BitsTransfer -Source $item.Url -Destination $dest -ErrorAction Stop - $size = [math]::Round((Get-Item $dest).Length / 1MB, 1) - Log " OK ($size MB)" + $svc.WaitForStatus('Stopped', (New-TimeSpan -Seconds 60)) + Write-Host " CcmExec netjes gestopt" } catch { - Log " MISLUKT: $($_.Exception.Message)" - Log " Handmatig downloaden via bovenstaande URL." + Write-Host " CcmExec hangt, force kill..." + Stop-Process -Name CcmExec -Force + Start-Sleep -Seconds 5 } } -Log "" -Log ('=' * 70) -Log "Klaar: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Log "Rapport: $logFile" -Log "URL-lijst: $urlFile" -Log "Bestanden: $outDir" \ No newline at end of file +Write-Host "[7/8] CcmExec starten..." +Start-Service ccmexec +Start-Sleep -Seconds 10 + +Write-Host "[8/8] SCCM cycles triggeren..." +$triggers = @( + '{00000000-0000-0000-0000-000000000021}', + '{00000000-0000-0000-0000-000000000022}', + '{00000000-0000-0000-0000-000000000113}', + '{00000000-0000-0000-0000-000000000114}' +) +foreach ($t in $triggers) { + Write-Host " - Trigger $t" + Invoke-WmiMethod -Namespace root\ccm -Class SMS_Client -Name TriggerSchedule -ArgumentList $t | Out-Null +} + +Write-Host "" +Write-Host "Klaar. Geef de scan 10-15 min voordat je Software Center checkt." \ No newline at end of file