Public/Get-PendingRebootStatus.ps1

<#
.SYNOPSIS
    This function searches for any operations that awaiting a system reboot.
.DESCRIPTION
    This function searches the Windows registry for any operations that require a system reboot, most importantly a Windows update.
.EXAMPLE
    PS C:\> Get-PendingRebootStatus
 
    ComputerName PendingReboot PendingRebootReasons
    ------------ ------------- --------------------
    DESKTOP-RFR3S01 True {FileRename}
 
    This example grabs the local computers pending reboot status. Currently it is only waiting on a file rename which is urgent.
.INPUTS
    [string[]] ComputerName
.OUTPUTS
    PSCustomObject
.NOTES
    Uses CimClass StdRegProv to grab registry information.
#>

function Get-PendingRebootStatus {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [Alias("CN","Name","MachineName")]
        [string[]]$Computername = $env:COMPUTERNAME
    )

    Begin{
        #Keys to use to reference each regsitry hive
        $HKEY_LOCAL_MACHINE = 2147483650

        #return codes
        <#
            RC = 0 for success
            RC = 1 for key read with no default value
            RC = 2 for key not found
            RC = 6 for invalid hive
        #>


        #Registry Paths to check
        $Updates = "SOFTWARE\Microsoft\Updates" #value UpdateExeVolatile is anything other than 0
        $FileRename = "SYSTEM\CurrentControlSet\Control\Session Manager" #value PendingFileRenameOperations, PendingFileRenameOperations2 exists
        $RebootRequired = "SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" #key RebootRequired or PostRebootReporting exists
        $Pending = "SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending" #GUID subkeys exists
        $RunOnce = "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" #value DVDRebootSignal exist
        $ComponentBS = "Software\Microsoft\Windows\CurrentVersion\Component Based Servicing" #keys RebootPending,RebootInProgress,PackagesPending exits
        $CBSValues = @("RebootPending","RebootInProgress","PackagesPending")
        $CurrentRebootAttempts = "SOFTWARE\Microsoft\ServerManager" #key CurrentRebootAttempts exists
        $NetLogin = "SYSTEM\CurrentControlSet\Services\Netlogon" #values JoinDomain, AvoidSpnSet exits
        $NetLoginValues = @("JoinDomain","AvoidSpnSet")
        $ActiveComputerName = "SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName" #value ComputerName is different than `
        #Value ComputerName in HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName is different
        $FutureName = "SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName"

    } #Begin

    Process{
        foreach ($computer in $Computername){
            if (Test-Connection -ComputerName $computer -Quiet -Count 1){
                $PendingReboot = $false
                $PendingRebootReasons = [System.Collections.Generic.List[string]]::New()
                Write-Information "[$Computer] is reachable" -Tags "Process"
                try{
                    $CimSession = New-CimConnection -ComputerName $computer -ErrorAction Stop
                    $RemoteRegistry = Get-CimClass -Namespace "root\default" -ClassName StdRegProv -CimSession $CimSession -ErrorAction Stop
                    Write-Information "[$computer]: started a new cim session and connected to remote registry"
                    
                    $UpdatesResults = $RemoteRegistry | Invoke-CimMethod -Name "GetDWORDValue" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$Updates;sValueName="UpdateExeVolatile"} -CimSession $CimSession
                    if ($UpdatesResults.ReturnValue -eq 0 -and $UpdatesResults.uValue -ne 0){
                        Write-Information "UpdateExeVolatile value does not equal 0" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("MSUpdates")
                    }

                    $FileRenameResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumValues" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$FileRename} -CimSession $CimSession
                    $ContainsFileNameValues = ($FileRenameResults.sNames -Contains "PendingFileRenameOperations" -or $FileRenameResults.sNames -Contains "PendingFileRenameOperations2")
                    if ($FileRenameResults.ReturnValue -eq 0 -and $ContainsFileNameValues){
                        Write-Information "FileNameOpertions values exists" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("FileRename")
                    }

                    $RebootRequiredResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumKey" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$RebootRequired} -CimSession $CimSession
                    $ContainsRebootValues = ($RebootRequiredResults.sNames -Contains "RebootRequired" -or $RebootRequiredResults.sNames -Contains "PostRebootReporting")
                    if ($RebootRequiredResults.ReturnValue -eq 0 -and $ContainsRebootValues){
                        Write-Information "RebootRequired value exists" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("WindowsUpdates")
                    }

                    $PendingResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumKey" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$Pending} -CimSession $CimSession
                    if ($PendingResults.ReturnValue -eq 0 -and $null -ne $PendingResults.sNames){
                        Write-Information "GUID keys exists under Pending key exits" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("ServicesPending")
                    }

                    $RunOnceResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumValues" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$RunOnce} -CimSession $CimSession
                    if ($RunOnceResults.ReturnValue -eq 0 -and $RunOnceResults.sNames -contains "DVDRebootSignal"){
                        Write-Information "DVDRebootSignal value exits" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("RunOnce")
                    }

                    $ComponentBSResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumKey" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyname=$ComponentBS} -CimSession $CimSession
                    if ($ComponentBSResults.ReturnValue -eq 0){
                        $ComponentBSResults.sNames | where {$_ -in $CBSValues} | ForEach-Object -Process {
                            $PendingReboot = $true
                            Write-Information "$_ key exits" -Tags "Process"
                            $PendingRebootReasons.Add($_)
                        }
                    }

                    $CurrentRebootAttemptsResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumKey" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyname=$CurrentRebootAttempts} -CimSession $CimSession
                    if ($CurrentRebootAttemptsResults.ReturnValue -eq 0 -and $CurrentRebootAttemptsResults.sNames -contains "CurrentRebootAttempts"){
                        Write-Information "CurrentRebootAttempt key exits" -Tags "Process"
                        $PendingReboot = $true
                        $PendingRebootReasons.Add("CurrentRebootAttempts")
                    }

                    $NetLoginResults = $RemoteRegistry | Invoke-CimMethod -Name "EnumValues" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$NetLogin} -CimSession $CimSession
                    if ($NetLoginResults.ReturnValue -eq 0){
                        $NetLoginResults.sNames | where {$_ -in $NetLoginValues} | ForEach-Object -Process {
                            $PendingReboot = $true
                            Write-Information "$_ value exits" -Tags "Process"
                            $PendingRebootReasons.Add($_)
                        }
                    }

                    $ActiveComputerNameResults = $RemoteRegistry | Invoke-CimMethod -Name "GetStringValue" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$ActiveComputerName;sValueName="ComputerName"} -CimSession $CimSession
                    $FutureNameResults =  $RemoteRegistry | Invoke-CimMethod -Name "GetStringValue" -Arguments @{hDefKey=$HKEY_LOCAL_MACHINE;sSubKeyName=$FutureName;sValueName="ComputerName"} -CimSession $CimSession
                    if ($ActiveComputerName.ReturnValue -eq 0 -and $FutureNameResults.ReturnValue -eq 0){
                        if ($ActiveComputerNameResults.sValue -eq $FutureNameResults.sValue){
                            Write-Information "Pending computer name change" -Tags "Process"
                            $PendingReboot = $true
                            $PendingRebootReasons.Add("PendingNameChange")
                        }
                    }

                    [PSCustomObject]@{
                        ComputerName = $computer
                        PendingReboot = $PendingReboot
                        PendingRebootReasons = $PendingRebootReasons
                    }
                    $CimSession | Remove-CimSession
                }
                catch{
                    $PSCmdlet.WriteError($_)
                }
            }
            else{
                Write-Error "[$computer] is unreachable"
            }
        } #foreach computer
    } #process
}