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"
}