Restart computer in Pending Reboot Status with no user logged in

I am working on combining 2 scripts to check if a computer is on pending reboot and restart it if there is no user logged in.
Below is the script. When I run it locally it works, but when I push it through Kbox it restarts the computer even if I am logged in.
Any help will be appreciated.

#Based on <http://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542&gt;
function Test-RebootRequired 
{
    $result = @{
        CBSRebootPending =$false
        WindowsUpdateRebootRequired = $false
        FileRenamePending = $false
        SCCMRebootPending = $false
		}

    #Check CBS Registry
    $key = Get-ChildItem "HKLM:Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -ErrorAction SilentlyContinue
    if ($key -ne $null) 
    {
        $result.CBSRebootPending = $true
    }
   
    #Check Windows Update
    $key = Get-Item "HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -ErrorAction SilentlyContinue
    if($key -ne $null) 
    {
        $result.WindowsUpdateRebootRequired = $true
    }

    #Check PendingFileRenameOperations
    $prop = Get-ItemProperty "HKLM:SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -ErrorAction SilentlyContinue    
	if($prop -ne $null) 
    {
       $result.FileRenamePending = $true    }
    
    #Check SCCM Client <http://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542/view/Discussions#content&gt;
    try 
    { 
        $util = [wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities"
        $status = $util.DetermineIfRebootPending()
        if(($status -ne $null) -and $status.RebootPending){
            $result.SCCMRebootPending = $true
        }
    }catch{}

    #Return Reboot required
    return $result.ContainsValue($true)
} 
#Now Check if there is no user logged in to reboot.
if(Test-RebootRequired -eq "True")
{
   $QuiryLoggedUser = quser
 If (!$QuiryLoggedUser) 
            {
            Write-Output 'No user logged in.'
            shutdown -r -t 0 -d U:00:00
            }

    else{
       Write-Output 'Computer in use.'
        }

}

Just curious, would KBOX be the Dell KACE Appliance? Others might want to know what that is.

Kbox is Dell-Quest endpoint management and inventory appliance. We use it for endpoints inventory, patching, pushing script (run as system), and many.
KACE is the name of the appliance and Kbox is the name of the application.

When troubleshooting I noticed this log.

Please do not post images of text. Instead post the plain text formatted as code.

Thanks in advance.

You could try providing the full path:

c:\Windows\System32\quser.exe

I have tried it and it’s giving me relatively the same error message.

#Now Check if there is no user logged in to reboot.
if(Test-RebootRequired -eq "True")
{
$QuiryLoggedUser = c:\Windows\System32\quser.exe
 If (!$QuiryLoggedUser) 
            {
            Write-Output 'No user logged in.'
            #shutdown -r -t 0 -d U:00:00
            }

    else{
       Write-Output 'Computer in use.'
        }

}
else{ return "False"} 
<#
c:\Windows\System32\quser.exe : The term 'c:\Windows\System32\quser.exe' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
path is correct and try again.
At C:\ProgramData\Quest\KACE\kbots_cache\packages\kbots\173\RestartComputerOnPendingRebootStatus.ps1:36 char:20
+ $QuiryLoggedUser = c:\Windows\System32\quser.exe
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (c:\Windows\System32\quser.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
No user logged in.
#>

I missed that. Sorry!

What about this:

$QuiryLoggedUser = & "C:\Windows\System32\quser.exe"

Still giving the error.

Running as SYSTEM
& : The term 'C:\Windows\System32\quser.exe' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At C:\ProgramData\Quest\KACE\kbots_cache\packages\kbots\173\RestartComputerOnPendingRebootStatus.ps1:36 char:22
+ $QuiryLoggedUser = & "C:\Windows\System32\quser.exe"
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (C:\Windows\System32\quser.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
No user logged in.

There are other ways of determining if there is a user logged on or not. You may try a different apporach.

A more PowerShelly way could be to use WMI/CIM

(Get-CimInstance -ClassName Win32_ComputerSystem).Username

I have tried that but it does not get the RDP user. The result is blank when the user is RDPing in.

PS C:\temp\Upgrade> (Get-CimInstance -ClassName Win32_ComputerSystem).Username

PS C:\temp\Upgrade> C:\Windows\System32\quser.exe
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
>lkossi              rdp-tcp#3           2  Active          .  4/15/2022 7:51 AM

PS C:\temp\Upgrade> 

I found this and I am trying to combine with the check reboot.

#Now Check if there is no user logged in to reboot.

Function Get-LoggedInUser {

    [CmdletBinding()]
        param(
            [Parameter(
                Mandatory = $false,
                ValueFromPipeline = $true,
                ValueFromPipelineByPropertyName = $true,
                Position=0
            )]
            [string[]] $ComputerName = $env:COMPUTERNAME,
 
 
            [Parameter(
                Mandatory = $false
            )]
            [Alias("SamAccountName")]
            [string]   $UserName
        )
 
    BEGIN {}
 
    PROCESS {
        foreach ($Computer in $ComputerName) {
            try {
                $Computer = $Computer.ToUpper()
                $SessionList = quser /Server:$Computer 2>$null
                if ($SessionList) {
                    $UserInfo = foreach ($Session in ($SessionList | select -Skip 1)) {
                        $Session = $Session.ToString().trim() -replace '\s+', ' ' -replace '>', ''
                        if ($Session.Split(' ')[3] -eq 'Active') {
                            [PSCustomObject]@{
                                ComputerName = $Computer
                                UserName     = $session.Split(' ')[0]
                                SessionName  = $session.Split(' ')[1]
                                SessionID    = $Session.Split(' ')[2]
                                SessionState = $Session.Split(' ')[3]
                                IdleTime     = $Session.Split(' ')[4]
                                LogonTime    = $session.Split(' ')[5, 6, 7] -as [string] -as [datetime]
                            }
                        } else {
                            [PSCustomObject]@{
                                ComputerName = $Computer
                                UserName     = $session.Split(' ')[0]
                                SessionName  = $null
                                SessionID    = $Session.Split(' ')[1]
                                SessionState = 'Disconnected'
                                IdleTime     = $Session.Split(' ')[3]
                                LogonTime    = $session.Split(' ')[4, 5, 6] -as [string] -as [datetime]
                            }
                        }
                    }
 
                    if ($PSBoundParameters.ContainsKey('Username')) {
                        $UserInfo | Where-Object {$_.UserName -eq $UserName}
                      } else {
                        $UserInfo | Sort-Object LogonTime
                    }
                }
            } catch {
                Write-Error $_.Exception.Message
 
            }
        }
    }
 
    END {}
}

if((Test-RebootRequired -eq "True") -and ((Get-LoggedInUser).sessionState -ne "Active"))
{
            Write-Output 'No user logged in.'
            shutdown -r -t 0 -d U:00:00
}
else{ return "False"}

When I tried the function only I get this error:

Running with credntials provided: domain [rochmn] user [admpctest]
Get-LoggedInUser : The term 'quser' is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that
the path is correct and try again.
At C:\ProgramData\Quest\KACE\kbots_cache\packages\kbots\173\GetUserLoggedIn.ps1:69 char:1
+ Get-LoggedInUser | Out-File C:\temp\UserloggedIn.txt
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-LoggedInUser
Launched Process: powershell.exe

But When I run it locally, it gets me the user logged in.

    END {}
} 
Get-LoggedInUser | Out-File C:\temp\UserloggedIn.txt

PS C:\temp\Upgrade> Get-LoggedInUser


ComputerName : COMPUTER-50319
UserName     : lkossi
SessionName  : rdp-tcp#4
SessionID    : 2
SessionState : Active
IdleTime     : .
LogonTime    : 4/15/2022 7:51:00 AM

I don’t understand. :roll_eyes:

Again … if you have issues using the quser.exe you may try another approach. It does not make that much sense to waste your time troubleshooting a non working solution when you could easily get an equally valid result with another solution.

Does query user or qwinsta give the same error?

I totally agree. I was looking for away to query any user even the user that is RDPing into that computer.

Yes the query user gives the same error. I have not tried the qwinsta yet. I will try it tomorrow and let you know.

I don’t get why this should make any difference!? :thinking: :man_shrugging:t4: There are always ways to circumvent annoying obstacles. :wink:

If we’re talking about domain joined computers where you have administrative access to with PowerShell remoting you can query the registry for the key “Volatile Environment”. It will return the logged on users no matter if they are loggod on remotely or locally.

$ComputerName =  'ComputerName'
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
        Get-Childitem -Path Registry::HKEY_USERS\ -ea 0 -exclude ".default" |
        ForEach-Object { Get-ChildItem Registry::$_ } |
        Where-Object { $_.Name -like "*Volatile Environment" } | 
        Get-ItemProperty -Name username |
        ForEach-Object {
            [PSCustomObject]@{
                UserName = $_.Username
                RegPath  = $_.PSParentPath
                FSPath   = "$(Split-Path $env:public -Parent)\$($_.Username)"
            }
        }
}
2 Likes

Nice!

Get-Childitem -Path Registry::HKEY_USERS\ -ea 0 -exclude ".default" | ForEach-Object {
    Get-ChildItem Registry::$_
} | Where-Object Name -like "*Volatile Environment" | ForEach-Object {
    $ht = [ordered]@{}

    foreach($prop in $_.property){
        $ht.$prop = $_.GetValue($prop)
    }

    [PSCUstomObject]$ht
}
1 Like