, ,

SCCM Script: Fix Software Update Store

Overview

I developed this tool, Fix-DGMSCCMUpdateStore.ps1, to assist in fixing Windows UpdateStore Corruption (Datastore.edb) on SCCM Client Computers. On the SCCM client machine, the Windows UpdateStore Datastore.edb in Windows\Software Distribution\.. contains scan results. Over time, this may become corrupted which can stop updating from occurring on the client machine. Additionally, an error might be seen on the client application log reporting wuaueng.dll (1668) SUS20ClientDataStore: Database C:\WINDOWS\SoftwareDistribution\DataStore\DataStore.edb requires logfiles xx-yy in order to recover successfully.

Fix-DGMSCCMUpdateStore Tool

The tool ill automatically attempt to fix the Windows Update Store on an array of SCCM client computers imported via a .CSV file. When run, the tool will perform the following tasks on each computer within the .CSV:

  • Stop the Windows Update Service
  • Move SoftwareDistribution to a backup location
  • Start Windows Update Service
  • Recreate SoftwareDistribution

The tool requires the –csvfile argument, which is the path to a .CSV file containing one column, Hostname, with the hostnames listed in the column and can be run as in the example below.

Fix-DGMSCCMUpdateStore Log File

The utility will create a log file that is compatible with the CMTrace tool, which includes the thread, time, state and component for each process.


PowerShell Script: Fix-DGMSCCMUpdateStore.ps1

<# .Synopsis Fix the Windows UpdateStore on an array of SCCM clients. .DESCRIPTION The Windows UpdateStore Datastore.edb in Windows\Software Distribution\.. contains scan results. This may become corrupted. This tool will fix it on an array of computers imported. .EXAMPLE Fix-DMGSCCMUpdateStore -CSVFile .\Fix-DMGSCCMUpdateStore-Import.csv #> 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}>" -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}>" -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-DMGSCCMUpdateStore { [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 { if ($CSVFile -ne $null){ Write-Host Importing $CSVFile... $csv = import-csv "$CSVFile" }else{ $csv = [PSCustomObject]@{ Hostname = $Hostname} } $service1 = "wuauserv" $service2 = "bits" Write-Host ========================================= Write-Host SCCM Fix Windows Update Store by dmaiolo Write-Host ========================================= Write-Host "v0.2 (2017-12-11)" New-DGMLogFile -message ("Starting Logging for Fix-DMGSCCMUpdateStore") -component "Main()" -type 1 } Process { $computers = @(); $csv | foreach-object { $h = $_.Hostname #Test if machine is online if(Test-Connection -ComputerName $h -count 2 -quiet){ Write-Host "Online: $h" -ForegroundColor Green #Stop Windows Update service try{ (get-service -ComputerName $h -Name $service1 -ErrorAction Stop).Stop() New-DGMLogFile -message ("Stopped $service1 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Stop $service1 service on $h.") -component "Main()" -type 3 } #Sleep 10 seconds to give service enough time to react Write-Host "Sleeping 5 Seconds..." Start-Sleep -s 5 #Stop BITS service try{ (get-service -ComputerName $h -Name $service2 -ErrorAction Stop).Stop() New-DGMLogFile -message ("Stopped $service2 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Stop $service2 service on $h.") -component "Main()" -type 3 } #Sleep 5 seconds to give service enough time to react Write-Host "Sleeping 5 Seconds..." Start-Sleep -s 5 #Rename the software update store $sourcepath = "\\$($h)\c$\Windows\SoftwareDistribution" $destinationpath = "\\$($h)\c$\Windows\SoftwareDistribution_$(Get-Date -Format dd-MM-yyyy)" $destinationpath2 = "\\$($h)\c$\Windows\SoftwareDistribution_$(Get-Date -Format dd-MM-yyyy)" #Appending destination path if script already run today if (Test-Path $destinationpath){ $n=0 while ((Test-Path $destinationpath2) -eq $true){ New-DGMLogFile -message ("Backup location $destinationpath2 already exists.") -component "Main()" -type 1 ++$n $destinationpath2 = $destinationpath + "-" + $n } $destinationpath = $destinationpath2 } Write-Host "Renaming $sourcepath..." try{ Move-Item -Path $sourcepath -Destination $destinationpath -Force New-DGMLogFile -message ("Renamed SoftwareDistribution to $destinationpath.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Rename SoftwareDistribution to $destinationpath.") -component "Main()" -type 3 } #Start the Windows Update service try{ (get-service -ComputerName $h -Name $service1 -ErrorAction Stop).Start() New-DGMLogFile -message ("Started $service1 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Start $service1 service on $h.") -component "Main()" -type 3 } #Start the BITS service try{ (get-service -ComputerName $h -Name $service2 -ErrorAction Stop).Start() New-DGMLogFile -message ("Started $service2 service on $h.") -component "Main()" -type 1 } catch{ New-DGMLogFile -message ("Could NOT Start $service2 service on $h.") -component "Main()" -type 3 } #Give the services 5 seconds to wake up and create new folders Start-Sleep -s 5 #Verify new folder was created Write-Host "Checking new folder recreation..." if(Test-Path("\\$($h)\c$\Windows\SoftwareDistribution")){ New-DGMLogFile -message ("\\$($h)\c$\Windows\SoftwareDistribution was recreated.") -component "Main()" -type 1 } else{ New-DGMLogFile -message ("\\$($h)\c$\Windows\SoftwareDistribution could NOT be recreated.") -component "Main()" -type 3 } } else{ #Machine is offline New-DGMLogFile -message ("Offline: $h.") -component "Main()" -type 2 } } } End { Write-Host =============================================================== Write-Host Log File of Results Generated at $path\Fix-DMGSCCMUpdateStore_$(Get-Date -Format dd-MM-yyyy).log VIEW WITH CMTRACE.EXE New-DGMLogFile -message ("Ending Logging for Fix-DMGSCCMUpdateStore") -component "Main()" -type 1 } } $VerboseLogging = "true" [bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging) $Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGSCCMUpdateStore_$(Get-Date -Format dd-MM-yyyy).log" $Global:MaxLogSizeInKB = 10240 $Global:ScriptName = 'Fix-DMGSCCMUpdateStore.ps1' $Global:ScriptStatus = 'Success'
0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *