1
$qusertest = quser | Out-String


if ([string]::IsNullOrEmpty($qusertest)){
    Restart-Computer -Force
} else {
    Write-Output $qusertest; exit 0
}

I am testing out code to automatically reboot computers in a list that are over a certain up time limit and have no users online. This is part of my testing scripts and for some reason, even if the output of the quser command returns information, it will restart the computer no matter what.

Can someone help me understand what logic is that I am missing that causes this?

PS C:\WINDOWS\system32> C:\Users\user\Documents\Working Scripts\qusertest logging.ps1
$qusertest -eq $null => 'False'
$qusertest.Length => '162'
$qusertest => 
' USERNAME      SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
>user           rdp-tcp#0           2  Active          .  11/24/2025 3:17 PM
'
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
>user          rdp-tcp#0           2  Active          .  11/24/2025 3:17 PM

Here is the logging output when testing the code against a live host and below is one when its against a logged out host, one thing is that this code is being sent through a patch management system when being tested against machines. Could that have been causing the issues? I have censored some user information for privacy sake. Also upon testing it today, it does not seem to be giving the same results so it may have been a random error. No changes to the original code set were made.

No User exists for *
$qusertest -eq $null => 'False'
$qusertest.Length => '0'
$qusertest => ''
Restart Required
13
  • On my system [string]::IsNullOrEmpty($qusertest) evaluates to False. Commented Nov 24 at 22:05
  • 3
    I don't think the code you're showing would ever produce the symptom you describe. Can you give an example of a non-empty $qusertest value that exhibits the symptom? Commented Nov 24 at 22:15
  • just FYI - the Out-String cmdlet seems to ALWAYS add a cr/lf to the end of whatever you send to it. that includes sending it nothing at all - so your test will always return FALSE since there is something there. Commented Nov 25 at 2:19
  • 1
    @mklement0 -- oh! that makes sense ... i just couldn't figure out ANY way to make Out-String not produce the usual cr/lf ending. thank you for the info! [grin] Commented Nov 25 at 17:15
  • 1
    My pleasure, @RLDailey: Note that it is typically the case that cmdlets that do not receive any input also produce no (success) output, and the absence of stdout output from an external program is the same as a PowerShell-native command not producing output. Out-String, as an aggregating cmdlet (similar to Measure-Object, for instance), still produces output in the absence of input, but then omits the trailing newline it normally (and questionably) appends; in other words: without input it outputs an empty string. Commented Nov 25 at 18:31

1 Answer 1

3

As some comments have already pointed out, if [string]::IsNullOrEmpty() returns $true, then the string is $null or empty.
The only way that quser would "return information", but its output still be "$null or empty", is when quser can't find a session (or when an error occurs) - it will then write to stderr, which is not captured by default with an assignment; you'd have to redirect the stderr stream to stdout using 2>&1 to capture that as well.
That aside:

  • You don't need the Out-String to collect output of console applications, because those are already returned as plain strings; Out-String is mainly useful after formatting cmdlets like Format-Table.
  • You should exclude the session with the > at the beginning - that indicates the session that is running the command.
  • You should (probably) only query for active sessions, depending on your interpretation of 'online'. Disconnected sessions might linger for weeks ...

Here's something that should get you started; note that I've garnished the Restart-Computer with a WhatIf, just in case:

# Collect stderr together with stdout, and stringify the error records (automatically generated when stderr is redirected); also write the output to the host:
$quser = & 'C:\Windows\system32\quser.exe' 2>&1 | ForEach-Object {"$_"; Write-Host "$_" -ForegroundColor Cyan}
$restart = $false
If ($quser -like '*Error*') {
    $quser | Write-Error
} ElseIf ($quser -eq 'No User exists for *') {
    $restart = $true
} Else {
    $activeSessions = $quser |
        Select-Object -Skip 1 |               # Header line
        Where-Object {$_ -notlike '>*'} |     # Own session
        Where-Object {$_ -match '\sActive\s'} # Only active sessions
    If ($activeSessions) {
        Write-Warning 'The following sessions are still active:'
        $activeSessions | Write-Warning
    } Else {
        $restart = $true
    }
}
If ($restart) {
    Restart-Computer -Force -WhatIf
}

And finally a caveat when redirecting stderr this way:
If the $ErrorActionPreference variable is set to 'Stop' in Windows PowerShell 5.x, any stderr output will automatically generate a terminating error, instead of capturing the output! See also Redirecting stderr / the error stream can trigger script-terminating errors #4002. This is not the case anymore in PowerShell Core 7.x.

Sign up to request clarification or add additional context in comments.

2 Comments

+1 for some useful techniques and information, but note that the code in the question should work, assuming that the OP wants to treat disconnected sessions the same as active ones and reasonably assuming that the code is run from the invisible services session - e.g. via a service or a scheduled task configured to run whether or not a user is logged on.
As an aside re Out-String: Out-String may be used to capture output from external programs as a single, multiline string (given that PowerShell streams such output line by line, which, with two or more lines results in an array when captured in a variable). However, this is marred by a trailing newline getting blindly appended (see GitHub issue #14444), so something like (quser) -join [Environment]::NewLine is usually preferable.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.