WSUS

Auto Approve / Decline Updates

Bu script filitreye girecek güncellemelerin otomatik olarak onaylanması ve filitre dışında kalan (Days den önceki) güncellemelerin reddedilmesini sağlar. Scripte parametre olarak gün, ürün(ler), sınıflandırma(lar), güncelleme adı (içerir şeklinde yazılabilir) ve Hedef bilgisayar grubu verilebilir. Boş bırakılan parametre değerlendirmeye alınmaz.

function Manage-WsusUpdates {
    param (
        [int]$Days = 30,

        [string[]]$Products,
        [string[]]$Classifications,
        [string[]]$Titles,
        [string]$TargetGroupName = "All Computers",

        [string]$WsusServer = "localhost",
        [bool]$UseSsl = $false,
        [int]$Port = 8530,

        [switch]$DryRun
    )

    [void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
    $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer, $UseSsl, $Port)

    $cutoffDate = (Get-Date).AddDays(-$Days)

    $targetGroup = $wsus.GetComputerTargetGroups() | Where-Object { $_.Name -eq $TargetGroupName }
    if (-not $targetGroup) {
        Write-Error "Target WSUS group not found: $TargetGroupName"
        return
    }

    $allUpdates = $wsus.GetUpdates()
    $approvedCount = 0
    $declinedCount = 0

    foreach ($update in $allUpdates) {
        # Dynamic filter checks
        $matchesProduct = $true
        $matchesClass = $true
        $matchesTitle = $true

        if ($Products) {
            $matchesProduct = ($update.ProductTitles | Where-Object { $Products -contains $_ }).Count -gt 0
        }

        if ($Classifications) {
            $matchesClass = $Classifications -contains $update.UpdateClassificationTitle
        }

        if ($Titles) {
            $matchesTitle = $false
            foreach ($titleFilter in $Titles) {
                if ($update.Title -like "*$titleFilter*") {
                    $matchesTitle = $true
                    break
                }
            }
        }

        if ($matchesProduct -and $matchesClass -and $matchesTitle) {
            $creationDate = $update.CreationDate

            if ($creationDate -ge $cutoffDate -and -not $update.IsDeclined) {
                $alreadyApproved = $update.GetUpdateApprovals() | Where-Object {
                    $_.ComputerTargetGroupId -eq $targetGroup.Id -and $_.Action -eq 'Install'
                }

                if (-not $alreadyApproved) {
                    if ($DryRun) {
                        Write-Host "[DRY-RUN] Would APPROVE: $($update.Title)"
                    } else {
                        try {
                            $update.Approve([Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install, $targetGroup)
                            Write-Host "Approved: $($update.Title)"
                            $approvedCount++
                        } catch {
                            Write-Warning "Error while approving: $($update.Title) - $($_.Exception.Message)"
                        }
                    }
                } else {
                    Write-Host "Already approved: $($update.Title)"
                }
            }
            elseif ($creationDate -lt $cutoffDate -and -not $update.IsDeclined) {
                if ($DryRun) {
                    Write-Host "[DRY-RUN] Would DECLINE: $($update.Title)"
                } else {
                    try {
                        $update.Decline()
                        Write-Host "Declined: $($update.Title)"
                        $declinedCount++
                    } catch {
                        Write-Warning "Error while declining: $($update.Title) - $($_.Exception.Message)"
                    }
                }
            }
        }
    }

    if ($DryRun) {
        Write-Host "`nSimulation completed. No updates were actually approved or declined."
    } else {
        Write-Host "Operation completed. Total approved: $approvedCount | Total declined: $declinedCount"
    }
}

Usage

Varsayılan kullanım (localhost, HTTP 8530):

Manage-WsusUpdates -Days 30 -Products @("Windows 10") -Classifications @("Security Updates")

WSUS başka bir sunucuda çalışıyorsa:

Manage-WsusUpdates -WsusServer "SERVERNAME.DOMAIN.COM" -Days 7

HTTPS kullanıyorsan (genellikle port 8531):

Manage-WsusUpdates -WsusServer "SERVERNAME" -UseSsl $true -Port 8531

Başlık bazlı filtreleme:

Manage-WsusUpdates -Titles @("KB5034") -Days 14

Simülasyon modu (dry-run, sadece ne yapılacağını listeler):

Manage-WsusUpdates -Days 7 -Products @("Windows 10") -Classifications @("Security Updates") -DryRun

WSUS Export & Import PowerShell Script

function Invoke-WsusBackup {
    param (
        [ValidateSet("Export", "Import")]
        [string]$Mode,

        [string]$WsusToolsPath = "C:\Program Files\Update Services\Tools",
        [string]$ContentSourcePath = "C:\WSUS\WsusContent",
        [string]$UpdateServicesPackagesPath = "C:\WSUS\UpdateServicesPackages",
        [string]$TargetFolder = "D:\WSUSBackup"
    )

    $logFile = Join-Path $TargetFolder "WsusBackup.log"

    function Write-Log {
        param ([string]$Message)
        $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        $entry = "$timestamp`t$Message"
        Add-Content -Path $logFile -Value $entry
        Write-Host $Message
    }

    function Export-Wsus {
        $exportXml = Join-Path $TargetFolder "export.xml"
        $exportLog = Join-Path $TargetFolder "export.log"
        $contentTargetPath = Join-Path $TargetFolder "WsusContent"
        $packagesTargetPath = Join-Path $TargetFolder "UpdateServicesPackages"

        Write-Log "=== EXPORT STARTED ==="

        if (!(Test-Path $TargetFolder)) {
            New-Item -Path $TargetFolder -ItemType Directory | Out-Null
            Write-Log "Backup folder created: $TargetFolder"
        }

        & "$WsusToolsPath\wsusutil.exe" export $exportXml $exportLog
        Write-Log "Metadata export completed: $exportXml"

        if (Test-Path $ContentSourcePath) {
            robocopy $ContentSourcePath $contentTargetPath /MIR /ZB /NP /R:2 /W:5 >> $logFile
            Write-Log "WsusContent copied to: $contentTargetPath"
        }

        if (Test-Path $UpdateServicesPackagesPath) {
            robocopy $UpdateServicesPackagesPath $packagesTargetPath /MIR /ZB /NP /R:2 /W:5 >> $logFile
            Write-Log "UpdateServicesPackages copied to: $packagesTargetPath"
        }

        Write-Log "=== EXPORT COMPLETED ==="
    }

    function Import-Wsus {
        $exportXml = Join-Path $TargetFolder "export.xml"
        $exportLog = Join-Path $TargetFolder "export.log"
        $contentTargetPath = Join-Path $TargetFolder "WsusContent"
        $packagesTargetPath = Join-Path $TargetFolder "UpdateServicesPackages"

        Write-Log "=== IMPORT STARTED ==="

        if (!(Test-Path $exportXml)) {
            Write-Log "ERROR: Export XML not found: $exportXml"
            return
        }

        & "$WsusToolsPath\wsusutil.exe" import $exportXml $exportLog
        Write-Log "Metadata import completed"

        if (Test-Path $contentTargetPath) {
            robocopy $contentTargetPath $ContentSourcePath /MIR /ZB /NP /R:2 /W:5 >> $logFile
            Write-Log "WsusContent restored to: $ContentSourcePath"
        }

        if (Test-Path $packagesTargetPath) {
            robocopy $packagesTargetPath $UpdateServicesPackagesPath /MIR /ZB /NP /R:2 /W:5 >> $logFile
            Write-Log "UpdateServicesPackages restored to: $UpdateServicesPackagesPath"
        }

        Write-Log "=== IMPORT COMPLETED ==="
    }

    switch ($Mode) {
        "Export" { Export-Wsus }
        "Import" { Import-Wsus }
        default {
            Write-Host "Usage examples:"
            Write-Host "  Invoke-WsusBackup -Mode Export -TargetFolder D:\WSUSBackup"
            Write-Host "  Invoke-WsusBackup -Mode Import -TargetFolder D:\WSUSBackup"
        }
    }
}

Bu PowerShell fonksiyonu, WSUS yapılandırmasını ve içeriklerini (örn. WsusContent, UpdateServicesPackages) dışa veya içe aktarmanı sağlar. Özellikle yedekleme ve offline taşıma senaryoları için uygundur.

Parametreler

Parametre
Tür
Açıklama

-Mode

string

Zorunlu. "Export" (Dışa Aktar) veya "Import" (İçe Aktar) olmak zorundadır.

-WsusToolsPath

string

Opsiyonel. wsusutil.exe dosyasının bulunduğu klasör. Varsayılan: C:\Program Files\Update Services\Tools

-ContentSourcePath

string

Opsiyonel. WsusContent klasörünün bulunduğu veya kopyalanacağı yer. Varsayılan: C:\WSUS\WsusContent

-UpdateServicesPackagesPath

string

Opsiyonel. UpdateServicesPackages klasörünün bulunduğu veya hedeflendiği dizin. Varsayılan: C:\WSUS\UpdateServicesPackages

-TargetFolder

string

Opsiyonel. Yedeklerin saklanacağı veya yedekten geri yükleneceği klasör. Varsayılan: D:\WSUSBackup

Usage

Örnek 1: WSUS verisini ve içeriğini dışa aktar (Export)

Invoke-WsusBackup -Mode Export
  • Metadata D:\WSUSBackup\export.xml olarak dışa aktarılır

  • İçerik klasörleri (WsusContent, UpdateServicesPackages) belirtilen hedefe kopyalanır

  • Log dosyası oluşturulur: D:\WSUSBackup\WsusBackup.log

Örnek 2: WSUS verisini ve içeriğini yedekten geri yükle (Import)

Invoke-WsusBackup -Mode Import
  • D:\WSUSBackup\export.xml içinden metadata içe aktarılır

  • İçerik dosyaları C:\WSUS altına kopyalanır

Örnek 3: Özel bir yedekleme klasörü ile kullan

Invoke-WsusBackup -Mode Export -TargetFolder "E:\Yedekler\WSUS2025"

Örnek 4: Özel WSUS kurulum dizinleri ile kullanım

Invoke-WsusBackup -Mode Export `
    -WsusToolsPath "D:\WSUS\Tools" `
    -ContentSourcePath "D:\WSUS\Data\Content" `
    -UpdateServicesPackagesPath "D:\WSUS\Data\Packages" `
    -TargetFolder "E:\Yedekler\WSUS_Full"

Oluşan Dosyalar ve Klasörler

Dosya/Klasör
Açıklama

export.xml

WSUS metadata (yapılandırma) yedeği

export.log

wsusutil log dosyası

WsusContent\

Güncelleme içerik klasörü

UpdateServicesPackages\

Ek paket içerik klasörü

WsusBackup.log

Tüm işlemlere dair özel log dosyası

İpuçları

  • Yönetici olarak çalıştırmayı unutmayın.

  • Log dosyası sayesinde tüm işlemler takip edilebilir.

  • Offline WSUS kopyalama, test ortamına klonlama, veya felaket kurtarma senaryoları için idealdir.

  • Task Scheduler ile otomatik zamanlama yapılabilir.

Last updated