BekaertDeslee-InstallWU.ps1


<#PSScriptInfo
 
.VERSION 2.6
 
.GUID 8b665e36-b497-4349-bc08-7e41a72ee3b0
 
.AUTHOR admin.descampd
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>
 



<#
 
.DESCRIPTION
Bekaert Deslee Windows Updater


Requires -Version 5.1
Requires -RunAsAdministrator
 
#>

#Requires -Version 5.1
#Requires -RunAsAdministrator

[CmdletBinding()]
param(
    [switch]$AcceptAll
)

#region Module Check

if (-not (Get-Module -ListAvailable -Name PSWindowsUpdate)) {
    Write-Host "`n[!] PSWindowsUpdate module not found." -ForegroundColor Yellow
    $install = Read-Host "Install it now from PSGallery? (Y/N)"
    if ($install -match '^[Yy]') {
        Write-Host "Installing PSWindowsUpdate..." -ForegroundColor Cyan
        try {
            Install-Module -Name PSWindowsUpdate -Scope AllUsers -Force -ErrorAction Stop
            Write-Host "Module installed successfully.`n" -ForegroundColor Green
        }
        catch {
            Write-Error "Failed to install PSWindowsUpdate: $_"
            return
        }
    }
    else {
        Write-Host "Cannot continue without PSWindowsUpdate." -ForegroundColor Red
        return
    }
}

Import-Module PSWindowsUpdate -ErrorAction Stop

#endregion

#region Get Updates

Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " Windows Update Scanner" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan

Write-Host "Scanning for available updates..." -ForegroundColor Yellow
try {
    $updates = Get-WUList -ErrorAction Stop
}
catch [System.NullReferenceException] {
    Write-Host "`n[!] Cannot scan for updates — a reboot is pending from a previous installation." -ForegroundColor Yellow
    Write-Host " Please restart and re-run this script." -ForegroundColor Yellow
    return
}
catch {
    Write-Error "Failed to retrieve update list: $_"
    return
}

if (-not $updates -or $updates.Count -eq 0) {
    Write-Host "`n[OK] No updates available. System is up to date." -ForegroundColor Green
    return
}

#endregion

#region Display Updates

Write-Host "`nFound $($updates.Count) update(s):`n" -ForegroundColor Green
Write-Host ("{0,-4} {1,-12} {2,-10} {3}" -f "#", "KB Article", "Size", "Title") -ForegroundColor Cyan
Write-Host ("-" * 80) -ForegroundColor DarkGray

for ($i = 0; $i -lt $updates.Count; $i++) {
    $u = $updates[$i]
    $kb = if ($u.KBArticleIDs) { "KB$($u.KBArticleIDs -join ',')" } else { "N/A" }
    $sizeMB = if ($u.MaxDownloadSize) { "$([math]::Round($u.MaxDownloadSize / 1MB, 1)) MB" } else { "?" }
    Write-Host ("{0,-4} {1,-12} {2,-10} {3}" -f "[$($i+1)]", $kb, $sizeMB, $u.Title) -ForegroundColor White
}

Write-Host ("-" * 80) -ForegroundColor DarkGray

#endregion

#region Selection

$toInstall = [System.Collections.Generic.List[object]]::new()
$proceed   = $true

if ($AcceptAll) {
    $toInstall.AddRange($updates)
    Write-Host "`n-AcceptAll specified. All $($updates.Count) updates queued." -ForegroundColor Yellow
}
else {
    Write-Host "`nOptions:" -ForegroundColor Cyan
    Write-Host " [A] Install ALL updates"
    Write-Host " [S] Select updates manually"
    Write-Host " [Q] Quit`n"

    do {
        $choice = Read-Host "Choose"
    } until ($choice -match '^[AaSsQq]$')

    switch ($choice.ToUpper()) {
        'Q' {
            Write-Host "Aborted." -ForegroundColor Yellow
            $proceed = $false
        }
        'A' {
            Write-Host "`nEnter numbers to EXCLUDE (comma-separated), or press Enter to keep all:" -ForegroundColor Yellow
            $excludeInput = Read-Host "Exclude"

            $excludeIndices = @()
            if ($excludeInput.Trim() -ne '') {
                $excludeIndices = $excludeInput -split ',' |
                    ForEach-Object { $_.Trim() } |
                    Where-Object   { $_ -match '^\d+$' } |
                    ForEach-Object { [int]$_ }
            }

            for ($i = 0; $i -lt $updates.Count; $i++) {
                if (($i + 1) -notin $excludeIndices) {
                    $toInstall.Add($updates[$i])
                }
            }

            Write-Host "`nUpdates queued for installation:" -ForegroundColor Cyan
            Write-Host ("-" * 80) -ForegroundColor DarkGray
            foreach ($u in $toInstall) {
                $kb = if ($u.KBArticleIDs) { "KB$($u.KBArticleIDs -join ',')" } else { "N/A" }
                Write-Host " [+] $kb - $($u.Title)" -ForegroundColor White
            }
            if ($excludeIndices.Count -gt 0) {
                Write-Host "`nExcluded:" -ForegroundColor DarkGray
                foreach ($idx in $excludeIndices) {
                    if ($idx -ge 1 -and $idx -le $updates.Count) {
                        $u  = $updates[$idx - 1]
                        $kb = if ($u.KBArticleIDs) { "KB$($u.KBArticleIDs -join ',')" } else { "N/A" }
                        Write-Host " [-] $kb - $($u.Title)" -ForegroundColor DarkGray
                    }
                }
            }
            Write-Host ("-" * 80) -ForegroundColor DarkGray

            do {
                $confirm = Read-Host "`nProceed with installing $($toInstall.Count) update(s)? (Y/N)"
            } until ($confirm -match '^[YyNn]$')

            if ($confirm -match '^[Nn]') {
                Write-Host "Aborted." -ForegroundColor Yellow
                $proceed = $false
            }
        }
        'S' {
            Write-Host "`nFor each update, press Y to queue it or N to skip it.`n" -ForegroundColor Cyan

            for ($i = 0; $i -lt $updates.Count; $i++) {
                $u  = $updates[$i]
                $kb = if ($u.KBArticleIDs) { "KB$($u.KBArticleIDs -join ',')" } else { "N/A" }
                Write-Host "[$($i+1)/$($updates.Count)] $kb - $($u.Title)" -ForegroundColor White

                do {
                    $ans = Read-Host " Install? (Y/N)"
                } until ($ans -match '^[YyNn]$')

                if ($ans -match '^[Yy]') {
                    $toInstall.Add($u)
                    Write-Host " -> Queued." -ForegroundColor Green
                }
                else {
                    Write-Host " -> Skipped." -ForegroundColor DarkGray
                }
            }
        }
    }
}

#endregion

#region Install

if ($proceed -and $toInstall.Count -eq 0) {
    Write-Host "`nNo updates selected." -ForegroundColor Yellow
    $proceed = $false
}

if ($proceed) {
    Write-Host "`n========================================" -ForegroundColor Cyan
    Write-Host " Installing $($toInstall.Count) update(s)" -ForegroundColor Cyan
    Write-Host "========================================`n" -ForegroundColor Cyan

    $index    = 0
    $succeeded = [System.Collections.Generic.List[string]]::new()
    $failed    = [System.Collections.Generic.List[string]]::new()

    foreach ($update in $toInstall) {
        $index++
        $kb    = if ($update.KBArticleIDs) { "KB$($update.KBArticleIDs -join ',')" } else { "N/A" }
        $title = $update.Title

        Write-Host "[$index/$($toInstall.Count)] Installing: $title" -ForegroundColor Cyan
        Write-Host " KB: $kb" -ForegroundColor DarkGray
        Write-Host " Started: $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor DarkGray

        try {
            Install-WindowsUpdate -UpdateID $update.Identity.UpdateID `
                                  -AcceptAll `
                                  -IgnoreReboot `
                                  -Verbose `
                                  -ErrorAction Stop

            Write-Host " [OK] Completed successfully at $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green
            $succeeded.Add("$kb - $title")
        }
        catch {
            Write-Host " [FAIL] Error: $_" -ForegroundColor Red
            $failed.Add("$kb - $title")
        }

        Write-Host ""
    }

    #endregion

    #region Summary

    Write-Host "========================================" -ForegroundColor Cyan
    Write-Host " Installation Summary" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan

    if ($succeeded.Count -gt 0) {
        Write-Host "`nSucceeded ($($succeeded.Count)):" -ForegroundColor Green
        $succeeded | ForEach-Object { Write-Host " [+] $_" -ForegroundColor Green }
    }

    if ($failed.Count -gt 0) {
        Write-Host "`nFailed ($($failed.Count)):" -ForegroundColor Red
        $failed | ForEach-Object { Write-Host " [-] $_" -ForegroundColor Red }
    }

    $rebootRequired = (Get-WURebootStatus -Silent -ErrorAction SilentlyContinue) -eq $true
    if ($rebootRequired) {
        Write-Host "`n[!] A reboot is required to complete installation. Please restart manually." -ForegroundColor Yellow
    }
    else {
        Write-Host "`n[OK] No reboot required." -ForegroundColor Green
    }

    if (-not $rebootRequired) {
        Write-Host "`n----------------------------------------" -ForegroundColor DarkGray
        Write-Host "Checking for remaining pending updates..." -ForegroundColor Yellow
        $pending = Get-WUList -ErrorAction SilentlyContinue

        if (-not $pending -or $pending.Count -eq 0) {
            Write-Host "[OK] No pending updates. System is fully up to date." -ForegroundColor Green
        }
        else {
            Write-Host "[!] $($pending.Count) update(s) still pending:" -ForegroundColor Yellow
            Write-Host ("{0,-4} {1,-12} {2,-10} {3}" -f "#", "KB Article", "Size", "Title") -ForegroundColor Cyan
            Write-Host ("-" * 80) -ForegroundColor DarkGray
            for ($i = 0; $i -lt $pending.Count; $i++) {
                $u      = $pending[$i]
                $kb     = if ($u.KBArticleIDs) { "KB$($u.KBArticleIDs -join ',')" } else { "N/A" }
                $sizeMB = if ($u.MaxDownloadSize) { "$([math]::Round($u.MaxDownloadSize / 1MB, 1)) MB" } else { "?" }
                Write-Host ("{0,-4} {1,-12} {2,-10} {3}" -f "[$($i+1)]", $kb, $sizeMB, $u.Title) -ForegroundColor White
            }
            Write-Host ("-" * 80) -ForegroundColor DarkGray
            Write-Host "Re-run this script to install the remaining updates." -ForegroundColor Yellow
        }
    }

    #endregion
}