Guida alla diagnosi dei problemi di Windows Update tramite PowerShell

La diagnosi dei problemi di Windows Update può essere un compito noioso per i professionisti IT, soprattutto quando si gestiscono più macchine. Ritardi o errori nel processo di aggiornamento possono portare a vulnerabilità di sicurezza, problemi di conformità e instabilità generale del sistema.

Lo script PowerShell fornito offre un approccio semplificato per diagnosticare e risolvere i problemi comuni di Windows Update, garantendo che i sistemi rimangano aggiornati e sicuri. In questo articolo si approfondiscono le funzionalità dello script per la diagnosi dei problemi di Windows Update opera eseguendo una serie di controlli sui principali componenti e servizi di Windows Update, e si discute di come lo script possa essere uno strumento prezioso per i professionisti IT e i Managed Service Provider (MSP).

Background

Windows Update è un componente fondamentale per mantenere l’integrità e la sicurezza di un sistema basato su Windows. Tuttavia, diversi fattori possono ostacolarne il buon funzionamento, dalle configurazioni errate dei servizi ai problemi di rete. I professionisti IT devono spesso affrontare l’arduo compito di risolvere questi problemi manualmente, processo che può richiedere molto tempo ed essere soggetto a errori umani.

Lo script PowerShell per la diagnosi dei problemi di Windows Update opera eseguendo una serie di controlli sui principali componenti e servizi di Windows Update fornito affronta questa sfida automatizzando il processo di diagnostica, e assicurando che i problemi più comuni vengano identificati e risolti rapidamente. Utilizzando questo script, i team IT possono mantenere l’integrità del sistema, ridurre i tempi di inattività e migliorare l’efficienza complessiva.

Lo script per la diagnosi dei problemi di Windows Update:

#Requires -Version 5.1

<#
.SYNOPSIS
    Diagnose Windows Update issues.
.DESCRIPTION
    Checks that CryptSvc, and bits or running or not
    Checks that wuauserv is running and the startup type is set correctly.
    Checks WaaSMedic plugins doesn't have issues. (Only applies to OS Build Version is greater than 17600).
    Checks if NTP is setup.
    Checks Windows Update logs for any errors in the last week.

.EXAMPLE
    (No Parameters)
    ## EXAMPLE OUTPUT WITHOUT PARAMS ##
    [Info] Last checked for updates on 4/29/2023
    [Issue] Windows Update has not checked for updates in over 30 days.

PARAMETER: -ResultsCustomField WindowsUpdate
    Saves results to a multi-line custom field.
.EXAMPLE
    -ResultsCustomField WindowsUpdate
    ## EXAMPLE OUTPUT WITH ResultsCustomField ##
    [Info] Last checked for updates on 4/29/2023
    [Issue] Windows Update has not checked for updates in over 90 days.
.OUTPUTS
    None
.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial Release
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://ninjastage2.wpengine.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [int]$Days = 30,
    [string]$ResultsCustomField
)

begin {
    if ($env:Days) {
        $Days = $env:Days
    }
    if ($env:resultscustomfield -notlike "null") {
        $ResultsCustomField = $env:resultscustomfield
    }
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }
    function Test-WaaSMedic {
        [CmdletBinding()]
        param()
        $WaaS = 0
        Try {
            $WaaS = New-Object -ComObject "Microsoft.WaaSMedic.1"
        }
        Catch {
            Write-Host "WaaS Medic Support: No"
        }
    
        Try {
            if ($WaaS -ne 0) {
                Write-Host "WaaS Medic Support: Yes"
                $Plugins = $WaaS.LaunchDetectionOnly("Troubleshooter")
    
                if ($Plugins -eq "") {
                    [PSCustomObject]@{
                        Id        = "WaaSMedic"
                        Detected  = $false
                        Parameter = @{"error" = $Plugins }
                    }
                }
                else {
                    [PSCustomObject]@{
                        Id        = "WaaSMedic"
                        Detected  = $true
                        Parameter = @{"error" = $Plugins }
                    }
                    "Plugins that might have errors: " + $Plugins | Out-String | Write-Host
                }
            }
        }
        Catch {
            Write-Host "WaaS Medic Detection: Failed"
        }
        Finally {
            # Release COM Object if we aren't running test cases
            if (-not $env:NinjaPesterTesting) {
                [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WaaS) | Out-Null
            }
        }
    }
    function Get-TimeSyncType {
        [string]$result = ""
        [string]$registryKey = "HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters"
        [string]$registryKeyName = "Type"
    
        if ((Test-Path $registryKey -ErrorAction SilentlyContinue)) {
            $registryEntry = Get-Item -Path $registryKey -ErrorAction SilentlyContinue
            if ($null -ne $registryEntry) {
                return Get-ItemPropertyValue -Path $registryKey -Name $registryKeyName
            }
        }
        return $result
    }
    function Test-ConnectedToInternet {
        $NLMType = [Type]::GetTypeFromCLSID('DCB00C01-570F-4A9B-8D69-199FDBA5723B')
        $INetworkListManager = [Activator]::CreateInstance($NLMType)  
        return ($INetworkListManager.IsConnectedToInternet -eq $true)
    }
    function Get-ComponentAndErrorCode([string]$msg) {	
        $Codes = [regex]::matches($msg, "0x[a-f0-9a-f0-9A-F0-9A-F0-9]{6,8}")
        if ($Codes.count -gt 1) {
            $CodeList = ""
            # there can be more than one error code can be returned for the same component at once
            foreach ($Code in $Codes) {
                $CodeList += "_" + $Code
            }
            return $CodeList
        }
        else {
            return $Codes[0].Value
        }
    }
    function Get-DatedEvents($EventLog) {
        $DatedEvents = @()
        if ($null -eq $EventLog) {
            return $null 
        }
        foreach ($Event in $EventLog) {
            #$eventMsg = $event.Message
            $DatedEvents += $Event.Message
        }
        return $DatedEvents
    }
    function Get-SystemEvents($EventSrc, $Time) {
        $Events = Get-WinEvent -ProviderName $EventsSrc -ErrorAction 0 | Where-Object { ($_.LevelDisplayName -ne "Information") -and (($_.Id -eq 20) -or ($_.Id -eq 25)) -and ($_.TimeCreated -gt $Time) }
        return $Events
    }
    function Get-HasWinUpdateErrorInLastWeek([switch]$AllLastWeekError) {
        $Events = @()
        $EventsSrc = "Microsoft-Windows-WindowsUpdateClient"
        $startTime = (Get-Date) - (New-TimeSpan -Day 8)
        $wuEvents = Get-SystemEvents $EventsSrc $startTime
        if ($null -eq $wuEvents) {
            return $null
        }
        $Events += Get-DatedEvents $wuEvents
        $LatestError = Get-ComponentAndErrorCode $Events[0]
        $ErrorList = @{}
        $ErrorList.add("latest", $LatestError)
        if ($AllLastWeekError) {
            foreach ($str in $Events) {
                $ECode = Get-ComponentAndErrorCode $str
                if ($null -ne $ECode -and !$ErrorList.ContainsValue($ECode)) {
                    $ErrorList.add($ECode, $ECode)
                }
            }
        }
        return $ErrorList
    }
    Function Get-LocalTime($UTCTime) {
        $strCurrentTimeZone = (Get-CimInstance -ClassName Win32_TimeZone).StandardName
        # If running test cases return current date
        if ($env:NinjaPesterTesting) {
            return Get-Date
        }
        $TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
        Return [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
    }
    $IssuesFound = $false
    $Log = [System.Collections.Generic.List[String]]::new()
}
process {
    if (-not (Test-IsElevated)) {
        Write-Error -Message "Access Denied. Please run with Administrator privileges."
        exit 1
    }

    if (-not $(Test-ConnectedToInternet)) {
        Write-Host "[Issue] Windows doesn't think it is connected to Internet."
        $IssuesFound = $true
    }

    # Check CryptSvc amd bits services
    $Service = Get-Service -Name CryptSvc
    if ($Service.StartType -notlike 'Automatic') {
        Write-Host "[Issue] (CryptSvc) CryptSvc service is set to $($Service.StartType) but needs to be set to Automatic"
        $Log.Add("[Issue] (CryptSvc) CryptSvc service is set to $($Service.StartType) but needs to be set to Automatic")
        $IssuesFound = $true
    }
    else {
        Write-Host "[Info] (CryptSvc) CryptSvc service is set to $($Service.StartType)"
        $Log.Add("[Info] (CryptSvc) CryptSvc service is set to $($Service.StartType)")
    }

    $Service = Get-Service -Name bits
    if ($Service.StartType -eq 'Disabled') {
        Write-Host "[Issue] (bits) BITS service is set to $($Service.StartType) but needs to be set to Manual"
        $Log.Add("[Issue] (bits) BITS service is set to $($Service.StartType) but needs to be set to Manual")
        $IssuesFound = $true
    }
    else {
        Write-Host "[Info] (bits) BITS service is set to $($Service.StartType)"
        $Log.Add("[Info] (bits) BITS service is set to $($Service.StartType)")
    }

    # Check that Windows Update service is running and isn't disabled
    $wuService = Get-Service -Name wuauserv -ErrorAction SilentlyContinue
    if ($wuService.Status -ne "Running") {
        $Service = Get-Service -Name wuauserv
        if ($Service.StartType -eq 'Disabled') {
            Write-Host "[Issue] (wuauserv) Windows Update service is set to $($Service.StartType) but needs to be set to Automatic (Trigger Start) or Manual"
            $Log.Add("[Issue] (wuauserv) Windows Update service is set to $($Service.StartType) but needs to be set to Automatic (Trigger Start) or Manual")
            $IssuesFound = $true
        }
        else {
            Write-Host "[Info] (wuauserv) Windows Update service is set to $($Service.StartType)"
            $Log.Add("[Info] (wuauserv) Windows Update service is set to $($Service.StartType)")
        }
    }

    # Check WaaSMedic
    $SupportWaaSMedic = [System.Environment]::OSVersion.Version.Build -gt 17600
    if ($SupportWaaSMedic) {
        $Plugins = Test-WaaSMedic
        $PluginIssues = $Plugins | Where-Object { $_.Parameter["error"] } | ForEach-Object {
            $PluginErrors = $_.Parameter["error"]
            "[Potential Issue] WaaSMedic plugin errors found with: $($PluginErrors)"
        }
        if ($PluginIssues.Count -gt 1) {
            Write-Host "[Issue] Found more than 1 plugin errors."
            $Log.Add("[Issue] Found more than 1 plugin errors.")
            $PluginIssues | Write-Host
            $IssuesFound = $true
        }
    }

    # Check if NTP is setup
    if ("NoSync" -eq (Get-TimeSyncType)) {
        Write-Host "[Issue] NTP not setup!"
        $Log.Add("[Issue] NTP not setup!")
        $IssuesFound = $true
    }

    # Check Windows Update logs
    $EventErrors = Get-HasWinUpdateErrorInLastWeek -AllLastWeekError
    if ($EventErrors.Count -gt 0) {
        if (![string]::IsNullOrEmpty($allError.Values)) {
            Write-Host "[Issue] Event Log has Windows Update errors."
            $Log.Add("[Issue] Event Log has Windows Update errors.")
            $errorCodes = $allError.Values -join ';'
            Write-Host "[Issue] Error codes found: $errorCodes"
            $Log.Add("[Issue] Error codes found: $errorCodes")
            $IssuesFound = $true
        }
    }

    # If no issues found, get number of days since the last check for updates happened
    if (-not $IssuesFound) {
        $LastCheck = Get-LocalTime $(New-Object -ComObject Microsoft.Update.AutoUpdate).Results.LastSearchSuccessDate

        Write-Host "[Info] Last checked for updates on $($LastCheck.ToShortDateString())"
        $Log.Add("[Info] Last checked for updates on $($LastCheck.ToShortDateString())")

        $LastCheckTimeSpan = New-TimeSpan -Start $LastCheck -End $(Get-Date)
        if ($LastCheckTimeSpan.TotalDays -gt $Days) {
            $Days = [System.Math]::Round($LastCheckTimeSpan.TotalDays, 0)
            Write-Host "[Issue] Windows Update has not checked for updates in over $Days days."
            $Log.Add("[Issue] Windows Update has not checked for updates in over $Days days.")
            $IssuesFound = $true
        }
    }

    if ($ResultsCustomField) {
        Ninja-Property-Set -Name $ResultsCustomField -Value $($Log | Out-String)
    }

    if ($IssuesFound) {
        exit 1
    }
    exit 0
}
end {
    
    
    
}

 

Analisi dettagliata

Lo script per la diagnosi dei problemi di Windows Update opera eseguendo una serie di controlli sui principali componenti e servizi di Windows Update, ognuno dei quali è essenziale per il corretto funzionamento del processo di aggiornamento. Ecco una descrizione passo per passo di come funziona lo script:

1. Controllo dell’elevazione dei permessi: Lo script per la diagnosi dei problemi di Windows Update inizia verificando che venga eseguito con i privilegi di amministratore, necessari per modificare i servizi di sistema e accedere a registri specifici.

2. Test di connettività Internet: Controlla se il sistema è connesso a Internet, un requisito fondamentale per scaricare gli aggiornamenti.

3. Controlli dello stato dei servizi:

  • Cryptographic Services (CryptSvc): Assicura che i Cryptographic Service siano impostati su “Automatico”, una configurazione necessaria per gestire i file di aggiornamento in modo sicuro.
  • Background Intelligent Transfer Service (BITS): Verifica che BITS non sia disattivato, poiché è responsabile del trasferimento dei file in background, compresi gli aggiornamenti.
  • Windows Update Service (wuauserv): Conferma che Windows Update service sia in esecuzione e impostato sul tipo di avvio corretto.

4. Verifica di WaaSMedic: Per i sistemi con una versione di build superiore a 17600, lo script per la diagnosi dei problemi di Windows Update controlla i plugin WaaSMedic, che sono responsabili della correzione automatica dei problemi legati all’aggiornamento.

5. Configurazione NTP: Lo script per la diagnosi dei problemi di Windows Update controlla se il Network Time Protocol (NTP) sia configurato correttamente, assicurando che l’orologio del sistema sia sincronizzato con una fonte di tempo esterna, un fattore cruciale per il processo di aggiornamento.

6. Analisi del registro eventi: Esamina i registri eventi di Windows Update alla ricerca di eventuali errori registrati nell’ultima settimana, identificando codici di errore specifici che possono indicare problemi di fondo.

7. Verifica dell’ultimo aggiornamento: Infine, lo script per la diagnosi dei problemi di Windows Update determina l’ultima volta che il sistema ha verificato la presenza di aggiornamenti. Se supera la soglia definita dall’utente (l’impostazione predefinita è 30 giorni), il problema viene segnalato.

Ognuno di questi controlli viene registrato e, se vengono riscontrati problemi, vengono riportati in un riepilogo che può essere salvato in un campo personalizzato per ulteriori analisi.

Casi d’uso potenziali

Immagina un professionista IT che gestisce una serie di workstation per una grande azienda. Un giorno, alcuni utenti segnalano che i loro sistemi non ricevono aggiornamenti da diverse settimane. Invece di controllare manualmente ogni sistema, il professionista IT distribuisce questo script per la diagnosi dei problemi di Windows Update su tutte le stazioni di lavoro.

Lo script identifica che il servizio Windows Update su diversi computer è configurato in modo errato e che il BITS è disabilitato su altri. Evidenzia inoltre che alcuni sistemi non verificano la presenza di aggiornamenti da oltre 60 giorni.

Con queste informazioni, il professionista IT può correggere rapidamente i problemi, assicurando che tutti i sistemi siano aggiornati, riducendo al minimo i rischi per la sicurezza e mantenendo la conformità con le policy aziendali.

Confronti

Questo script PowerShell offre un approccio più automatizzato e completo rispetto ai metodi tradizionali per la diagnosi dei problemi di Windows Update, come il controllo manuale degli stati dei servizi o la verifica dei registri degli eventi.

Sebbene strumenti basati su GUI come Windows Update Troubleshooter possano risolvere alcuni problemi, spesso non sono in grado di fornire informazioni dettagliate o di gestire più macchine contemporaneamente.

Questo script, invece, non solo identifica i problemi, ma offre anche approfondimenti chiari e utilizzabili, il che lo rende un’opzione migliore per gli ambienti IT su larga scala.

Domande frequenti

1. Questo script può risolvere i problemi che trova?

  • No, questo script è progettato per diagnosticare e segnalare i problemi. Tuttavia, fornisce informazioni sufficienti ai professionisti IT per permettergli di adottare le misure necessarie a risolvere i problemi manualmente.

2. Questo script per la diagnosi dei problemi di Windows Update è compatibile con tutte le versioni di Windows?

  • Lo script per la diagnosi dei problemi di Windows Update supporta Windows 10 e Windows Server 2016 e versioni successive, garantendo un’ampia applicabilità negli ambienti Windows moderni.

3. Cosa devo fare se lo script segnala un errore con i plugin WaaSMedic?

  • I problemi legati a WaaSMedic richiedono in genere un intervento manuale. Potrebbe essere necessario ripristinare il servizio WaaSMedic o utilizzare strumenti aggiuntivi per risolvere gli errori specifici del plugin.

Implicazioni

I risultati di questo script per la diagnosi dei problemi di Windows Update possono avere implicazioni significative per la sicurezza informatica. Identificare e risolvere tempestivamente i problemi di Windows Update può impedire che le vulnerabilità non patchate vengano sfruttate, riducendo il rischio di attacchi informatici.

Inoltre, garantire che gli aggiornamenti siano applicati in modo coerente aiuta a mantenere la stabilità del sistema, evitando interruzioni impreviste che potrebbero interrompere le operazioni aziendali.

Raccomandazioni

Quando utilizzi questo script per la diagnosi dei problemi di Windows Update, ricordati di:

  • Eseguirlo regolarmente: Incorporalo nel tuo programma di manutenzione ordinaria per garantire che i problemi legati agli aggiornamenti vengano individuati tempestivamente.
  • Analizzare attentamente i log: Presta attenzione ai dettagli dei log generati dallo script per la diagnosi dei problemi di Windows Update, perché possono fornire informazioni critiche sui problemi ricorrenti.
  • Integrarlo con strumenti di automazione: Per gli ambienti su larga scala, prendi in considerazione la possibilità di integrare questo script per la diagnosi dei problemi di Windows Update con piattaforme di automazione come NinjaOne, per semplificare il processo diagnostico su più sistemi.

Considerazioni finali

NinjaOne offre una potente piattaforma che fungere da complemento alle funzionalità di questo script per la diagnosi dei problemi di Windows Update. Integrando lo script nei flussi di lavoro automatizzati di NinjaOne, i professionisti IT possono migliorare la loro capacità di diagnosticare e risolvere i problemi di Windows Update su numerosi computer contemporaneamente.

Questa integrazione non solo fa risparmiare tempo, ma garantisce anche che tutti i sistemi rimangano sicuri e aggiornati, contribuendo in ultima analisi a un’infrastruttura IT più stabile e resiliente.

Passi successivi

La creazione di un team IT efficiente ed efficace richiede una soluzione centralizzata che funga da principale strumento per la fornitura di servizi. NinjaOne consente ai team IT di monitorare, gestire, proteggere e supportare tutti i dispositivi, ovunque essi si trovino, senza la necessità di una complessa infrastruttura locale.

Per saperne di più su NinjaOne Endpoint Management, fai un tour dal vivo, o inizia la tua prova gratuita della piattaforma NinjaOne.

Categorie:

Ti potrebbe interessare anche

×

Guarda NinjaOne in azione!

Inviando questo modulo, accetto La politica sulla privacy di NinjaOne.

Termini e condizioni NinjaOne

Cliccando sul pulsante “Accetto” qui sotto, dichiari di accettare i seguenti termini legali e le nostre condizioni d’uso:

  • Diritti di proprietà: NinjaOne possiede e continuerà a possedere tutti i diritti, i titoli e gli interessi relativi allo script (compreso il copyright). NinjaOne ti concede una licenza limitata per l’utilizzo dello script in conformità con i presenti termini legali.
  • Limitazione d’uso: Puoi utilizzare lo script solo per legittimi scopi personali o aziendali interni e non puoi condividere lo script con altri soggetti.
  • Divieto di ripubblicazione: In nessun caso ti è consentito ripubblicare lo script in una libreria di script appartenente o sotto il controllo di un altro fornitore di software.
  • Esclusione di garanzia: Lo script viene fornito “così com’è” e “come disponibile”, senza garanzie di alcun tipo. NinjaOne non promette né garantisce che lo script sia privo di difetti o che soddisfi le tue esigenze o aspettative specifiche.
  • Assunzione del rischio: L’uso che farai dello script è da intendersi a tuo rischio. Riconosci che l’utilizzo dello script comporta alcuni rischi intrinseci, che comprendi e sei pronto ad assumerti.
  • Rinuncia e liberatoria: Non riterrai NinjaOne responsabile di eventuali conseguenze negative o indesiderate derivanti dall’uso dello script e rinuncerai a qualsiasi diritto legale o di equità e a qualsiasi rivalsa nei confronti di NinjaOne in relazione all’uso dello script.
  • EULA: Se sei un cliente NinjaOne, l’uso dello script è soggetto al Contratto di licenza con l’utente finale (EULA) applicabile.