chore: commit uncommitted production changes for v16 migration

This commit is contained in:
Dave
2026-03-07 09:47:25 +01:00
parent 208212a883
commit 1fca135a83
89 changed files with 13362 additions and 635 deletions
+325
View File
@@ -0,0 +1,325 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Windows Update Diagnostics Script for TacticalRMM
.DESCRIPTION
Sammelt umfassende Diagnoseinformationen zum Windows Update Status.
Ausgabe erfolgt als strukturierter Text fuer TacticalRMM.
.NOTES
Version: 1.0
Datum: 2026-01-07
Fuer: MSP Documentation / TacticalRMM
#>
[CmdletBinding()]
param()
$ErrorActionPreference = "SilentlyContinue"
function Write-Section {
param([string]$Title)
Write-Output ""
Write-Output "=" * 60
Write-Output " $Title"
Write-Output "=" * 60
}
function Write-SubSection {
param([string]$Title)
Write-Output ""
Write-Output "--- $Title ---"
}
# Header
Write-Output "WINDOWS UPDATE DIAGNOSTICS"
Write-Output "Hostname: $env:COMPUTERNAME"
Write-Output "Datum: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "OS: $((Get-CimInstance Win32_OperatingSystem).Caption)"
Write-Output "Build: $([System.Environment]::OSVersion.Version.Build).$((Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').UBR)"
# ============================================================
# 1. WINDOWS UPDATE DIENSTE
# ============================================================
Write-Section "1. WINDOWS UPDATE DIENSTE"
$services = @(
@{Name="wuauserv"; DisplayName="Windows Update"},
@{Name="bits"; DisplayName="Background Intelligent Transfer"},
@{Name="cryptsvc"; DisplayName="Cryptographic Services"},
@{Name="msiserver"; DisplayName="Windows Installer"},
@{Name="TrustedInstaller"; DisplayName="Windows Modules Installer"}
)
foreach ($svc in $services) {
$service = Get-Service -Name $svc.Name -ErrorAction SilentlyContinue
if ($service) {
$startType = (Get-CimInstance Win32_Service -Filter "Name='$($svc.Name)'").StartMode
$status = if ($service.Status -eq "Running") { "[OK]" } else { "[!!]" }
Write-Output "$status $($svc.DisplayName) ($($svc.Name)): $($service.Status) / StartType: $startType"
} else {
Write-Output "[??] $($svc.DisplayName) ($($svc.Name)): Nicht gefunden"
}
}
# ============================================================
# 2. WSUS / WINDOWS UPDATE KONFIGURATION
# ============================================================
Write-Section "2. WINDOWS UPDATE KONFIGURATION"
Write-SubSection "Registry: WindowsUpdate Policy"
$wuPolicyPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
if (Test-Path $wuPolicyPath) {
$wuPolicy = Get-ItemProperty -Path $wuPolicyPath -ErrorAction SilentlyContinue
Write-Output "WUServer: $($wuPolicy.WUServer)"
Write-Output "WUStatusServer: $($wuPolicy.WUStatusServer)"
Write-Output "UseWUServer: $($wuPolicy.UseWUServer)"
Write-Output "DoNotConnectToWindowsUpdateInternetLocations: $($wuPolicy.DoNotConnectToWindowsUpdateInternetLocations)"
$auPath = "$wuPolicyPath\AU"
if (Test-Path $auPath) {
$auPolicy = Get-ItemProperty -Path $auPath -ErrorAction SilentlyContinue
Write-Output ""
Write-Output "AU Policy:"
Write-Output " NoAutoUpdate: $($auPolicy.NoAutoUpdate)"
Write-Output " AUOptions: $($auPolicy.AUOptions)"
Write-Output " ScheduledInstallDay: $($auPolicy.ScheduledInstallDay)"
Write-Output " ScheduledInstallTime: $($auPolicy.ScheduledInstallTime)"
Write-Output " UseWUServer: $($auPolicy.UseWUServer)"
}
} else {
Write-Output "Keine WSUS/GPO Konfiguration gefunden (Standard Windows Update)"
}
Write-SubSection "Registry: Windows Update Settings"
$wuSettingsPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate"
if (Test-Path $wuSettingsPath) {
$wuSettings = Get-ItemProperty -Path $wuSettingsPath -ErrorAction SilentlyContinue
Write-Output "AccountDomainSid: $($wuSettings.AccountDomainSid)"
Write-Output "SusClientId: $($wuSettings.SusClientId)"
}
# ============================================================
# 3. WINDOWS UPDATE HISTORIE
# ============================================================
Write-Section "3. WINDOWS UPDATE HISTORIE (letzte 20)"
try {
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
Write-Output "Gesamte Historie-Eintraege: $HistoryCount"
Write-Output ""
if ($HistoryCount -gt 0) {
$History = $Searcher.QueryHistory(0, [Math]::Min(20, $HistoryCount))
foreach ($Update in $History) {
$ResultCode = switch ($Update.ResultCode) {
0 { "NotStarted" }
1 { "InProgress" }
2 { "Succeeded" }
3 { "SucceededWithErrors" }
4 { "Failed" }
5 { "Aborted" }
default { "Unknown" }
}
$Status = if ($Update.ResultCode -eq 2) { "[OK]" } else { "[!!]" }
$Date = $Update.Date.ToString("yyyy-MM-dd HH:mm")
$Title = $Update.Title
if ($Title.Length -gt 60) { $Title = $Title.Substring(0, 57) + "..." }
Write-Output "$Status [$Date] $ResultCode"
Write-Output " $Title"
}
}
} catch {
Write-Output "Fehler beim Abrufen der Update-Historie: $_"
}
# ============================================================
# 4. AUSSTEHENDE UPDATES
# ============================================================
Write-Section "4. AUSSTEHENDE UPDATES"
try {
$Searcher = $Session.CreateUpdateSearcher()
$SearchResult = $Searcher.Search("IsInstalled=0")
Write-Output "Ausstehende Updates: $($SearchResult.Updates.Count)"
Write-Output ""
if ($SearchResult.Updates.Count -gt 0) {
foreach ($Update in $SearchResult.Updates) {
$Severity = if ($Update.MsrcSeverity) { $Update.MsrcSeverity } else { "Unspecified" }
$Size = [math]::Round($Update.MaxDownloadSize / 1MB, 1)
Write-Output "[$Severity] $($Update.Title)"
Write-Output " KB: $($Update.KBArticleIDs -join ', ') | Groesse: ${Size}MB | Downloaded: $($Update.IsDownloaded)"
}
} else {
Write-Output "Keine ausstehenden Updates gefunden."
}
} catch {
Write-Output "Fehler beim Suchen nach Updates: $_"
}
# ============================================================
# 5. LETZTE ERFOLGREICHE INSTALLATION
# ============================================================
Write-Section "5. LETZTE ERFOLGREICHE UPDATE-INSTALLATION"
try {
$LastSuccess = $null
$History = $Searcher.QueryHistory(0, $HistoryCount)
foreach ($Update in $History) {
if ($Update.ResultCode -eq 2) {
$LastSuccess = $Update
break
}
}
if ($LastSuccess) {
$DaysAgo = [math]::Round((Get-Date) - $LastSuccess.Date).TotalDays
Write-Output "Datum: $($LastSuccess.Date.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Output "Tage her: $DaysAgo"
Write-Output "Update: $($LastSuccess.Title)"
if ($DaysAgo -gt 60) {
Write-Output ""
Write-Output "[WARNUNG] Letztes erfolgreiches Update ist mehr als 60 Tage her!"
}
} else {
Write-Output "Kein erfolgreiches Update in der Historie gefunden!"
}
} catch {
Write-Output "Fehler: $_"
}
# ============================================================
# 6. SOFTWAREDISTRIBUTION ORDNER
# ============================================================
Write-Section "6. SOFTWAREDISTRIBUTION STATUS"
$sdPath = "$env:SystemRoot\SoftwareDistribution"
if (Test-Path $sdPath) {
$sdSize = (Get-ChildItem -Path $sdPath -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
$sdSizeMB = [math]::Round($sdSize / 1MB, 2)
Write-Output "Pfad: $sdPath"
Write-Output "Groesse: ${sdSizeMB} MB"
$downloadPath = "$sdPath\Download"
if (Test-Path $downloadPath) {
$dlSize = (Get-ChildItem -Path $downloadPath -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
$dlSizeMB = [math]::Round($dlSize / 1MB, 2)
Write-Output "Download-Ordner: ${dlSizeMB} MB"
}
$dataStorePath = "$sdPath\DataStore\DataStore.edb"
if (Test-Path $dataStorePath) {
$dbSize = [math]::Round((Get-Item $dataStorePath).Length / 1MB, 2)
Write-Output "DataStore.edb: ${dbSize} MB"
if ($dbSize -gt 500) {
Write-Output "[WARNUNG] DataStore.edb ist sehr gross - Reset empfohlen"
}
}
} else {
Write-Output "[FEHLER] SoftwareDistribution Ordner nicht gefunden!"
}
# ============================================================
# 7. WINDOWS UPDATE FEHLER (Event Log)
# ============================================================
Write-Section "7. WINDOWS UPDATE FEHLER (letzte 7 Tage)"
try {
$StartDate = (Get-Date).AddDays(-7)
$WUErrors = Get-WinEvent -FilterHashtable @{
LogName = 'System'
ProviderName = 'Microsoft-Windows-WindowsUpdateClient'
Level = 2,3 # Error, Warning
StartTime = $StartDate
} -MaxEvents 10 -ErrorAction SilentlyContinue
if ($WUErrors) {
Write-Output "Gefundene Fehler/Warnungen: $($WUErrors.Count)"
Write-Output ""
foreach ($Event in $WUErrors) {
$Level = if ($Event.Level -eq 2) { "[ERROR]" } else { "[WARN]" }
Write-Output "$Level [$($Event.TimeCreated.ToString('yyyy-MM-dd HH:mm'))] ID:$($Event.Id)"
Write-Output " $($Event.Message.Split("`n")[0])"
}
} else {
Write-Output "Keine Windows Update Fehler in den letzten 7 Tagen."
}
} catch {
Write-Output "Event Log konnte nicht abgefragt werden: $_"
}
# ============================================================
# 8. NETZWERK-KONNEKTIVITAET
# ============================================================
Write-Section "8. WINDOWS UPDATE KONNEKTIVITAET"
$testUrls = @(
"https://www.microsoft.com",
"https://update.microsoft.com",
"https://windowsupdate.microsoft.com"
)
foreach ($url in $testUrls) {
try {
$response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop
Write-Output "[OK] $url (Status: $($response.StatusCode))"
} catch {
Write-Output "[!!] $url (Fehler: $($_.Exception.Message))"
}
}
# ============================================================
# 9. ZUSAMMENFASSUNG
# ============================================================
Write-Section "9. ZUSAMMENFASSUNG"
$issues = @()
# Check services
$wuService = Get-Service -Name wuauserv -ErrorAction SilentlyContinue
if ($wuService.Status -ne "Running") {
$issues += "Windows Update Dienst laeuft nicht"
}
# Check last update age
if ($LastSuccess -and $DaysAgo -gt 60) {
$issues += "Letztes Update vor mehr als $DaysAgo Tagen"
}
# Check WSUS
if ((Test-Path $wuPolicyPath) -and $wuPolicy.UseWUServer -eq 1) {
$issues += "WSUS konfiguriert: $($wuPolicy.WUServer)"
}
# Check pending updates
if ($SearchResult -and $SearchResult.Updates.Count -gt 5) {
$issues += "$($SearchResult.Updates.Count) ausstehende Updates"
}
if ($issues.Count -eq 0) {
Write-Output "Status: OK - Keine offensichtlichen Probleme gefunden"
} else {
Write-Output "Status: PROBLEME ERKANNT"
Write-Output ""
foreach ($issue in $issues) {
Write-Output " [!] $issue"
}
}
Write-Output ""
Write-Output "=" * 60
Write-Output " DIAGNOSTICS ENDE"
Write-Output "=" * 60