|
Server : Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12 System : Windows NT SERVER-PC 10.0 build 26200 (Windows 11) AMD64 User : ServerPC ( 0) PHP Version : 8.2.12 Disable Function : NONE Directory : C:/Windows/diagnostics/system/WindowsUpdate/ |
Upload File : |
# Copyright � 2017, Microsoft Corporation. All rights reserved.
# =============================================================
# Load Utilities
#=================================================================================
. .\CL_Utility.ps1
. .\CL_SetupEnv.ps1
. .\CL_Service.ps1
#=================================================================================
# Get-DateLastWeek
# Function gets the last week starting from midnight
#=================================================================================
function Get-DateLastWeek()
{
$lastweek = (Get-Date) - (New-Timespan -day 8)
$lastweek = $lastweek.addminutes(-($lastweek.minute))
$lastweek = $lastweek.addhours(-($lastweek.hour))
$lastweek = $lastweek.addseconds(-($lastweek.second))
return $lastweek
}
#=================================================================================
# Get-ComponentAndErrorCode
#=================================================================================
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
}
}
#=================================================================================
# Get-DatedEvents
# Gets the dated events from given date to present date
#=================================================================================
function Get-DatedEvents($eventlog)
{
$datedEvents = @()
if($eventlog -eq $null)
{
return $null
}
foreach($event in $eventlog)
{
#$eventMsg = $event.Message
$datedEvents += $event.Message
}
return $datedEvents
}
#=================================================================================
# Get-SystemEvents
# Function to get the Windows Event logs
#=================================================================================
function Get-SystemEvents($eventSrc,$time)
{
$events = Get-WinEvent -ProviderName $eventsSrc -ErrorAction 0 | ?{($_.LevelDisplayName -ne "Information") -and (($_.Id -eq 20) -or ($_.Id -eq 25)) -and ($_.TimeCreated -gt $time)}
return $events
}
#=================================================================================
# HasWinUpdateErrorInLastWeek
#=================================================================================
function HasWinUpdateErrorInLastWeek([switch]$allLastWeekError)
{
$events = @()
$eventsSrc = "Microsoft-Windows-WindowsUpdateClient"
$startTime = (Get-Date) - (New-TimeSpan -Day 8)
$wuEvents = Get-SystemEvents $eventsSrc $startTime
if($wuEvents -eq $null)
{
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($ecode -ne $null -and !$errorList.ContainsValue($ecode))
{
$errorList.add($ecode,$ecode)
}
}
}
return $errorList
}
#*=================================================================================
# Get-AllErrorCodes
#*=================================================================================
function Get-AllErrorCodes()
{
return (HasWinUpdateErrorInLastWeek -AllLastWeekError)
}
function Test-ServiceStarted($serviceName)
{
<#
.DESCRIPTION:
Function that checks whether a service is started or not
.ARGUMENT:
ServiceName - Name of the service
.RETURNS:
<True> if service started otherwise <false>
#>
if($serviceName -eq $null)
{
return $false
}
$service=get-service $serviceName
if($service.status -ieq "running")
{
return $true
}
return $false
}
function Test-PostBack
{
[CmdletBinding()]
PARAM
(
[Alias('S')]
[Parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string] $CurrentScriptName
)
PROCESS
{
# Writing the trace to current directory
$CurrentScriptName = ("{0}.temp" -f [System.IO.Path]::GetFileNameWithoutExtension($CurrentScriptName))
if(Test-Path($CurrentScriptName))
{
return $true
}
'Executed' >> $CurrentScriptName
return $false
}
}
function Test-ConnectedToInternet
{
$NLMType = [Type]::GetTypeFromCLSID('DCB00C01-570F-4A9B-8D69-199FDBA5723B')
$INetworkListManager = [Activator]::CreateInstance($NLMType)
return ($INetworkListManager.IsConnectedToInternet -eq $true)
}
function Test-UpdateAvailable
{
# Default value to return in case we fail to search for updates
$results = $false
try
{
$PowerShell = [PowerShell]::Create()
[void]$PowerShell.AddScript({
$updateSession = New-Object -ComObject Microsoft.Update.Session
$updateSearcher = $updateSession.CreateUpdateSearcher()
$searchResult = $updateSearcher.Search("IsInstalled = 0")
return ($searchResult.Updates.Count -gt 0)
})
# Start executing the script block asynchronously in a separate thread in the current runspace
$AsyncTask = $PowerShell.BeginInvoke()
# Wait till IsCompleted is signalled or timeout expires
$AsyncTask.AsyncWaitHandle.WaitOne(60000) | Out-Null
if ($AsyncTask.IsCompleted -eq $false)
{
# If the async activity was not complete then terminate it. You will not have access to the results of the asynchronous invoke.
$PowerShell.Stop() | Out-Null
}
else
{
#Async activity completed before timeout. Retrieve the results.
$AsyncResultCollection = $PowerShell.EndInvoke($AsyncTask)
if (($AsyncResultCollection.Count -eq 1) -and ($AsyncResultCollection[0] -is [System.Boolean]))
{
$results = $AsyncResultCollection[0]
}
}
$PowerShell.Dispose() | Out-Null
}
catch
{}
return $results
}
function Get-PendingReboot
{
<#
SYNOPSIS:
Gets the pending reboot status on a local computer.
DESCRIPTION:
This function will query the registry on a local or remote computer and determine if the
system is pending a reboot, from Microsoft updates, Configuration Manager Client SDK, Pending Computer
Rename, Domain Join or Pending File Rename Operations. For Windows 2008+ the function will query the
CBS registry key as another factor in determining pending reboot state. "PendingFileRenameOperations"
and "Auto Update\RebootRequired" are observed as being consistent across Windows Server 2003 & 2008.
CBServicing : Component Based Servicing (Windows 2008+)
WindowsUpdate : Windows Update / Auto Update (Windows 2003+)
CCMClientSDK : SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value
PendingComputerRename : Detects either a computer rename or domain join operation (Windows 2003+)
PendingFileRename : PendingFileRenameOperations (Windows 2003+)
PendingFileRenameValue : PendingFileRenameOperations registry value; used to filter if needed, some Anti-Virus
leverage this key for def/dat removal, giving a false positive PendingReboot
EXAMPLE:
PS C:\> Get-PendingReboot
CBServicing : False
WindowsUpdate : True
CCMClient : False
PendingComputerRename : False
PendingFileRename : False
PendingFileRenameValue : {\??\C:\Users\Administrator\AppData\Local\Temp\nsz994B.tmp\p\syschk.dll, , \??\C:\Users\Administrator\AppData\Local\Temp\nsz994B.tmp\p\, ...}
RebootPending : True
This example will query the local machine for pending reboot information.
LINK:
Component-Based Servicing:
http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx
PendingFileRename/Auto Update:
http://support.microsoft.com/kb/2723674
http://technet.microsoft.com/en-us/library/cc960241.aspx
http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx
SCCM 2012/CCM_ClientSDK:
http://msdn.microsoft.com/en-us/library/jj902723.aspx
#>
try
{
$Computer = $env:COMPUTERNAME
# Setting pending values to false
$CBSRebootPending = $PendingComputerRename = $PendingFileRename = $SCCM = $Pending = $false
# Making registry connection to the computer
$HKLM = [UInt32] "0x80000002"
$WmiRegistryConnection = [WMIClass] "\\$Computer\root\default:StdRegProv"
# Querying the CBS Registry Key
$RegSubKeysCBS = $WmiRegistryConnection.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")
$CBSRebootPending = $RegSubKeysCBS.sNames -contains "RebootPending"
# Query WUAU from the registry
$RegWUAURebootRequired = $WmiRegistryConnection.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
$WUAURebootRequired = $RegWUAURebootRequired.sNames -contains "RebootRequired"
# Query PendingFileRenameOperations from the registry
$RegSubKeySM = $WmiRegistryConnection.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations")
$RegValuePFRO = $RegSubKeySM.sValue
# Query JoinDomain key from the registry - These keys are present if pending a reboot from a domain join operation
$Netlogon = $WmiRegistryConnection.EnumKey($HKLM,"SYSTEM\CurrentControlSet\Services\Netlogon").sNames
$PendingDomainJoin = ($Netlogon -contains 'JoinDomain') -or ($Netlogon -contains 'AvoidSpnSet')
# Query ComputerName and ActiveComputerName from the registry
$ActiveComputerName = $WmiRegistryConnection.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\","ComputerName")
$ComputerName = $WmiRegistryConnection.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\","ComputerName")
if (($ActiveComputerName -ne $ComputerName) -or $PendingDomainJoin)
{
$PendingComputerRename = $true
}
# If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true
if ($RegValuePFRO)
{
$PendingFileRename = $true
}
# Determine SCCM 2012 Client Reboot Pending Status
# To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0
$CCMClientSDK = $null
$CCMSplat = @{
NameSpace = 'ROOT\ccm\ClientSDK'
Class = 'CCM_ClientUtilities'
Name = 'DetermineIfRebootPending'
ComputerName = $Computer
ErrorAction = 'Stop'
}
try
{
$CCMClientSDK = Invoke-WmiMethod @CCMSplat
}
catch [System.UnauthorizedAccessException]
{
$CcmStatus = Get-Service -Name CcmExec -ComputerName $Computer -ErrorAction SilentlyContinue
if ($CcmStatus.Status -ne 'Running')
{
Write-Warning "$Computer`: Error - CcmExec service is not running."
$CCMClientSDK = $null
}
}
catch
{
$CCMClientSDK = $null
}
if ($CCMClientSDK)
{
if ($CCMClientSDK.ReturnValue -ne 0)
{
Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)"
}
if ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending)
{
$SCCM = $true
}
}
else
{
$SCCM = $null
}
# Creating Custom PSObject and Select-Object Splat
$SelectSplat = @{
Property = (
'CBServicing',
'WindowsUpdate',
'CCMClientSDK',
'PendingComputerRename',
'PendingFileRename',
'PendingFileRenameValue',
'RebootPending'
)}
New-Object -TypeName PSObject -Property @{
CBServicing = $CBSRebootPending
WindowsUpdate = $WUAURebootRequired
CCMClientSDK = $SCCM
PendingComputerRename = $PendingComputerRename
PendingFileRename = $PendingFileRename
PendingFileRenameValue = $RegValuePFRO
RebootPending = ($PendingComputerRename -or $CBSRebootPending -or $WUAURebootRequired -or $SCCM -or $PendingFileRename)
} | Select-Object @SelectSplat
}
catch
{
Write-Warning "$Computer`: $_"
# Updating diagnostics report
if ($ErrorLog) {
Out-File -InputObject "$Computer`,$_" -FilePath $ErrorLog -Append
}
}
}
function Get-PendingRebootOfflineUpdates
{
$updateSession = New-Object -ComObject "Microsoft.Update.Session"
$updateSession.ClientApplicationID = "Script to query updates"
$updateSearcher = $updateSession.CreateUpdateSearcher()
$updateSearcher.Online = 0
[array]$searchResult = [array]($updateSearcher.Search("IsPresent=1 and RebootRequired=1"))
[int]$result = ($searchResult.Updates).Count
if($result -ge 1)
{
return $true
}
return $false
}