SCCM Script: WUA Policy Error Fix

Overview

I developed this tool, Fix-DMGSCCMWUAPolicy.ps1,to help you mitigate WUA Policy issues that result in error 0x80004005 on the client-side WUAHandler.log file. This tool will attempt to resolve those issues.

Troubleshooting Error 0x80004005

When you deploy software updates, you add the updates to a SUG and then deploy the SUG to your clients. When you create the deployment, the update policy is sent to client computers, and the update content files are downloaded from a DP to the local cache on the client computer. The updates are then available for installation. After the deployment and the deployment policy have been created on the server, clients receive the policy on the next policy evaluation cycle. However, group policy issues can sometimes block these policies.

Root Cause of WSUS Error 0x80004005

If you receive error 0x80004005 in your WUAHandler.log file, then Group policy is likely overriding the local policy, not allowing the workstation to be patched or updated.

Resolution to WSUS Error 0x80004005

If you have this error, a few steps need to be carried out to resolve. The below script will automate this task against remotely against a set of imported computers. If the fix is not required, the utility will pass on to the next computer in the CSV file.

The utility will create a log file which is compatible with the CMTrace.exe tool.

log_file

PowerShell Script: Fix-DMGSCCMWUAPolicy.ps1


<#
.Synopsis
   Fix the WUA Policy Locally On The Client
.DESCRIPTION
   The tool, Fix-DMGSCCMWUAPolicy.ps1 was written by David Maiolo and will automatically fix WUA Policies
.EXAMPLE
   Fix-DMGSCCMWUAPolicy -CSVFile sccm_import.csv
.EXAMPLE
   Fix-DMGSCCMWUAPolicy -Hostname WORKSTATION01
#>


function New-DGMLogFile
{
  param (
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Global:Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}><thread={4}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}><thread={4}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
  if ($type -eq 'Error') { $Global:ScriptStatus = $type }

  if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
  {
    $log = $Global:LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 

function GetScriptDirectory
{
  $invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $invocation.MyCommand.Path
} 

function Fix-DMGSCCMWUAPolicy
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
                   [ValidateScript({(Test-Path $_)})]
                   $CSVFile,
        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 2')]
                   [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })]
                   [String]$Hostname
    )

    Begin
    {
        $path = (get-item -Path .).FullName 
        
        if ($CSVFile -ne $null){
            Write-Host Importing $CSVFile...
            $csv = import-csv "$CSVFile"
        }else{
            $csv = [PSCustomObject]@{
                Hostname = $Hostname}
        }
        Write-Host ==========================================
        Write-Host SCCM WUA Policy Error 0`x80070002 Fix Tool
        Write-Host ==========================================
        Write-Host "v0.1 (2017-12-20) by dmaiolo"
        New-DGMLogFile -message ("Starting Logging for Fix-DMGSCCMWUAPolicy") -component "Main()" -type 1 
    }
    Process
    {
    

    $computers = @();
        
    $csv | foreach-object {
        $h = $_.Hostname
    

        if(Test-Connection -ComputerName $h -Count 1 -Quiet){


            $g = $null
            $resultsfile = $null

            $resultsfile = "\\$h\c$\Windows\CCM\Logs\WUAHandler.log"
            #$resultsfile = "\\cs-msc\public\Temp\Noah\WUAHandler.log"
            $logLines = @()

            Write-Host $h`: Loading $resultsfile ...
            if (Test-Path $resultsfile){
                $g = Get-Content  $resultsfile -ErrorAction Stop
            }else{
                New-DGMLogFile -message ("$h`: $resultsfile Does Not Exist") -component "Main()" -type 3
            }
            
            $lastLine = $g.Length
            $WUAPolicyErrorFound = $false
            Write-Host $h`: Size of File`: $lastLine Lines

            for($i = $lastLine-1; $i -ge 0; $i--)
            {
                #if ($g[$i] -contains "*0x80004005*") { 
                #    Write-Host $g[$i]
                #    $WUAPolicyErrorFound = $true
                #    break
                $g[$i] -match '(?:.*)(0x80004005)' | out-null
                    #$logLines += ($h + ': ' + $matches[1] + ' on ' + $matches[3] + ' at ' + $matches[2])
                    if ($matches -ne $null){
                        if ($matches[1] -eq "0x80004005") { 
                            $WUAPolicyErrorFound = $true
                            break 
                        }
                    }
               
            }

            if($WUAPolicyErrorFound){
                New-DGMLogFile -message ("$h`: Unable to read existing WUA Group Policy object. 0x80004005. Fix requred.") -component "Main()" -type 2
                $sourcefile = "\\$h\c$\Windows\System32\GroupPolicy\Machine\Registry.pol"
                #$destinationfile = "\\$($h)\c$\Windows\System32\GroupPolicy\Registry_$(Get-Date -Format dd-MM-yyyy).pol"

                Write-Host "$h`: Removing $sourcefile..."
                if (Test-Path $sourcefile){
                    try{
                        Remove-Item -Path $sourcefile -Force
                        New-DGMLogFile -message ("$h`: Removed Policy File`: $sourcefile.") -component "Main()" -type 1
                    }
                    catch{
                        New-DGMLogFile -message ("$h`: Could NOT Remove Policy File`: $sourcefile.") -component "Main()" -type 3
                    }
                }else{
                    New-DGMLogFile -message ("$h`: File Does Not Exist`: $sourcefile.") -component "Main()" -type 3
                }

                Write-Host $h`: Sleeping 5 Seconds...
                sleep 5

                Write-Host "$h`: Running GPUdate `/Force..."
                Try{
                    Invoke-Command -ComputerName $h -ScriptBlock { gpupdate /force } -ErrorAction Stop
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Ran Succesfully") -component "Main()" -type 1
                }
                Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Did NOT Run Succesfully (errorcode 0x80090322 occurred while using Kerberos authentication: An unknown security error occurred.)") -component "Main()" -type 3
                    try {
                        $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                        Invoke-Expression -Command:"$command"
                        New-DGMLogFile -message ("$h`: WinRM Repair Ran Succesfully") -component "Main()" -type 1
                        }
                    catch{
                        New-DGMLogFile -message ("$h`: WinRM Repair NOT Succesfull") -component "Main()" -type 3
                    }
                }
                Catch{
                    New-DGMLogFile -message ("$h`: GPUpdate /Force Did NOT Run Succesfully (generic error)") -component "Main()" -type 3
                }

                Write-Host $h`: Sleeping 5 Seconds...
                sleep 5

                Write-Host "$h`: Updating the SCCM Store Policy..."
                Try{
                    Invoke-Command -ComputerName $h -ScriptBlock { 
                        $strAction = "{00000000-0000-0000-0000-000000000108}"

                        $WMIPath = "\\" + $Using:h + "\root\ccm:SMS_Client" 
                        $SMSwmi = [wmiclass] $WMIPath 
                        [Void]$SMSwmi.TriggerSchedule($strAction)
                     } -ErrorAction Stop
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was Succesful") -component "Main()" -type 1
                }
                Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was NOT Succesful (errorcode 0x80090322 occurred while using Kerberos authentication: An unknown security error occurred.)") -component "Main()" -type 3
                }
                Catch{
                    New-DGMLogFile -message ("$h`: Update of the SCCM Store Policy Was NOT Succesful (generic error)") -component "Main()" -type 3
                }

            }else{
                New-DGMLogFile -message ("$h`: No WUA Group Policy Object Errors Found. No Fix requred.") -component "Main()" -type 1
            }

        }
        else{
            New-DGMLogFile -message ("$h`: is offline.") -component "Main()" -type 2
        }
       }
    }
    End
    {
       Write-Host ===============================================================
       Write-Host Log File of Results Generated at $Global:LogFile VIEW WITH CMTRACE.EXE
       New-DGMLogFile -message ("Ending Logging for Fix-DMGSCCMWUAPolicy") -component "Main()" -type 1
    }
}

$VerboseLogging = "true"
[bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging)
#$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMWUAPolicy_$(Get-Date -Format dd-MM-yyyy).log"
$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMWUAPolicy.log"
$Global:MaxLogSizeInKB = 10240
$Global:ScriptName = 'Fix-DMGSCCMWUAPolicy.ps1' 
$Global:ScriptStatus = 'Success'

Leave a Comment

Your email address will not be published.