Home > Mobile >  How to get RDP Disconnected sessions using qwinsta command
How to get RDP Disconnected sessions using qwinsta command

Time:02-25

I have written a PS script to find any user who has a disconnected RDP session on remote servers, I am getting the exact output as I want but, using qwinsta query I want to get the details of user Logon Time and IDOL time as well, but I am unable to query that using Qwinsta command.

If I try with Query user I am getting an error in my script saying no user has been found. Please help to achieve the output.

The script I have written.

Code

## Clear Host Console
Clear-Host

## Define Variable for Server Count
$z = 0

##Set Default Script Location
Set-Location -Path "C:\Users\Desktop\Active or Disc users"

## Check if the old Report file exists or not
#$checkrep = Test-Path ".\Reports\RDP_Disconnected_Users_Report.html" 

## Provide List of Servers to Check for the Disconnected user session
$Servers = Get-Content ".\Servers\Servers.txt"

## Get Servers Count
$count = $Servers.count 

## Define Date for the Out file
$dt = Get-Date -Format yyyyMMdd
$Date = Get-Date

## Define Path for the Out File
$exportFile = ".\Out\RDP_DisConnected_Users.csv"

## Define Array for Storing the User sessions
$openSessions = @()

## Loop through each server to find the User Disconnected session
Foreach ($ServerName in $Servers)
{

#initiate counter for showing progress
    $z = $z   1

# Start writing progress 
Write-Progress -Activity "Processing Server: $z out of $count servers." -Status " Progress" -PercentComplete ($z/$Servers.count*100)

## Add the servers if you want to exclude any
$ExcludedServers = "EXCLUDESRV01", "EXCLUDESRV02", "EXCLUDESRV03"
If ($ExcludedServers -notcontains $ServerName)
{
#$user = quser | where {($_.User -ne "") -and ($_.Username -ne "Administrator")}
Write-Host "Getting session information for $ServerName"
$sessions = qwinsta /server $ServerName| ?{ $_ -notmatch '^ SESSIONNAME' } | %{
$item = "" | Select "ServerName", "Username", "Id", "State"
$item.ServerName = $ServerName
#$item.SessionName = $_.Substring(1,18).Trim()
$item.Username = $_.Substring(19,20).Trim()
$item.Id = $_.Substring(39,9).Trim()
$item.State = $_.Substring(48,8).Trim()
$item.IdleTime = $_.Substring().Trim()
$item.LogonTime = $_.Substring().Trim()
$item
}
$openSessions  = $sessions | where { ($_.Username -ne "") -and ($_.Username -ne "Administrator") -and ($_.State -ne "Active")}
}
Else { Write-Host "Skipping named computer $ServerName" -ForegroundColor Green}
}

$openSessions | Export-Csv "$exportFile" -NoTypeInformation

CodePudding user response:

You could use a helper function to get all remote session details, active or not and filter out the ones you want in your output.

As requested here not only the function, but a complete rewrite of your code:

function Get-RemoteSessions {
    [CmdletBinding()]
    param(
        [string[]]$ComputerName = 'localhost'
    )
    foreach ($Computer in $ComputerName) {
        Write-Verbose "Getting session information for $Computer"
        # create an object to fill in later
        $obj = "" | Select-Object UserName, @{Name = 'ComputerName'; Expression = {$Computer}}, 
                                  SessionName, ID, State, IdleTime, LogonTime, Error
        try {
            quser /server:$Computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
                $items = $_.Trim() -split '\s{2,}'
                $obj.UserName = $items[0].TrimStart(">")
                # If session is disconnected different fields will be selected
                if ($items[2] -like 'Disc*') {
                    $obj.SessionName = $null
                    $obj.Id          = $items[1]
                    $obj.State       = $items[2]
                    # IdleTime displays the number of minutes that have elapsed since the last keyboard or 
                    # mouse input from a session. Its format is number-of-days   hours:minutes
                    $obj.IdleTime    = $items[3]
                    $obj.LogonTime   = $items[4..($items.GetUpperBound(0))] -join ' '
                }
                else {
                    $obj.SessionName = $items[1]
                    $obj.Id          = $items[2]
                    $obj.State       = $items[3]
                    $obj.IdleTime    = $items[4]
                    $obj.LogonTime   = $items[5]
                }
                # reformat the IdleTime property
                $obj.IdleTime = '{0} days, {1} hours, {2} minutes' -f ([int[]]([regex]'^(?:(\d )\ )?(\d ):(\d )').Match($obj.IdleTime).Groups[1..3].Value | ForEach-Object { $_ })
                # output the object
                $obj
            }
        } 
        catch {
            $obj.Error = $_.Exception.Message
            $obj
        }
    }
}

## Clear Host Console
Clear-Host

$ExcludedServers = 'EXCLUDESRV01', 'EXCLUDESRV02', 'EXCLUDESRV03'
## Read the list of Servers excluding the ones in $ExcludedServers
$Servers = Get-Content -Path 'C:\Users\Desktop\Active or Disc users\Servers\Servers.txt' | 
           Where-Object { $ExcludedServers -notcontains $_ }

# get all remote sessions on all servers
$allSessions = Get-RemoteSessions -ComputerName $Servers -Verbose

# filter the open sessions from the $allRemoteUsers
$openSessions = $allSessions| Where-Object {$_.Username -ne 'Administrator' -and $_.State -notlike 'Disc*'}
# and do the same for the disconnected sessions
$disconnected = $allSessions | Where-Object {$_.Username -ne 'Administrator' -and $_.State -like 'Disc*' }

## Define Path for the Out File and make sure the path for the output file exists
$reportPath = 'C:\Users\Desktop\Active or Disc users\Out'
$null = New-Item -Path $reportPath -ItemType Directory -Force

if (@($openSessions).Count) {
    # write a file for the open sessions
    $outFile = Join-Path -Path $reportPath -ChildPath ('RDP_Connected_Users_{0:yyyyMMdd}.csv' -f (Get-Date))
    $openSessions | Export-Csv -Path $outFile -NoTypeInformation
}
else {
    Write-Host "No open user sessions found"
}

if (@($disconnected).Count) {
    # and another for the disconnected sessions
    $outFile = Join-Path -Path $reportPath -ChildPath ('RDP_DisConnected_Users_{0:yyyyMMdd}.csv' -f (Get-Date))
    $disconnected | Export-Csv -Path $outFile -NoTypeInformation
}
else {
    Write-Host "No disconnected sessions found"
}
  • Related