Reputation: 25
I wrote a script that will refine users that are either disconnected or have an idle time of over than 60 min. I've already set-up these parameters and the filter works well, however; instead of disconnecting the specific user in that server, the script disconnects the server as a whole
I am utilizing two other functions, one of which I added directly into the script. the other comes from Get-LoggedOnUser.ps1 The Disconnect-LoggedOnUser and Get-LoggedOnUser are intended to work together. I kept the instructions for log out script. I've included my full script in this GitHub gist
Any assistance or suggestion is greatly appreciated! All relevant code below:
Description
-----------
This command dot sources the script to ensure the Disconnect-LoggedOnUser function is available in your current PowerShell session
.EXAMPLE
Disconnect-LoggedOnUser -ComputerName server01 -Id 5
Description
-----------
Disconnect session id 5 on server01
.EXAMPLE
.\Get-LoggedOnUser.ps1 -ComputerName server01,server02 | Where-Object {$_.UserName -eq 'JaapBrasser'} | Disconnect-LoggedOnUser -Verbose
<#My script#>
<#
.SYNOPSIS
Convert output from CMD's 'query.exe user' to usable objects.
.DESCRIPTION
Take the text based output returned by 'query.exe user' and convert it to objects that can be manipulated in PowerShell.
.PARAMETER Name
Computer name to run query.exe against.
.EXAMPLE
PS C:\> Convert-QueryToObjects -Name server01
ComputerName Username SessionState SessionType
------------ -------- ------------ -----------
server01 bobsmith Disconnected
server01 janedoe Active tcp-rdp
#>
function Disconnect-LoggedOnUser {
<#
.SYNOPSIS
Function to disconnect a RDP session remotely
.DESCRIPTION
This function provides the functionality to disconnect a RDP session remotely by providing the ComputerName and the SessionId
.PARAMETER ComputerName
This can be a single computername or an array where the RDP sessions will be disconnected
.PARAMETER Id
The Session Id that that will be disconnected
.NOTES
Name: Disconnect-LoggedOnUser
Author: Jaap Brasser
DateUpdated: 2015-06-03
Version: 1.0
Blog: http://www.jaapbrasser.com
.LINK
http://www.jaapbrasser.com
.EXAMPLE
. .\Disconnect-LoggedOnUser.ps1
Description
-----------
This command dot sources the script to ensure the Disconnect-LoggedOnUser function is available in your current PowerShell session
.EXAMPLE
Disconnect-LoggedOnUser -ComputerName server01 -Id 5
Description
-----------
Disconnect session id 5 on server01
.EXAMPLE
.\Get-LoggedOnUser.ps1 -ComputerName server01,server02 | Where-Object {$_.UserName -eq 'JaapBrasser'} | Disconnect-LoggedOnUser -Verbose
Description
-----------
Use the Get-LoggedOnUser script to gather the user sessions on server01 and server02. Where-Object filters out only the JaapBrasser user account and then disconnects the session by piping the results into Disconnect-LoggedOnUser while displaying verbose information.
#>
param(
[Parameter(
Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position=0
)]
[string[]]
$ComputerName,
[Parameter(
Mandatory,
ValueFromPipelineByPropertyName
)]
[int[]]
$Id
)
begin {
$OldEAP = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
}
process {
foreach ($Computer in $ComputerName) {
$Id | ForEach-Object {
Write-Verbose "Attempting to disconnect session $Id on $Computer"
try {
rwinsta $_ /server:$Computer
Write-Verbose "Session $Id on $Computer successfully disconnected"
} catch {
Write-Verbose 'Error disconnecting session displaying message'
Write-Warning "Error on $Computer, $($_.Exception.Message)"
}
}
}
}
end {
$ErrorActionPreference = $OldEAP
}
}
function Convert-QueryToObjects
{
[CmdletBinding()]
[Alias('QueryToObject')]
[OutputType([PSCustomObject])]
param
(
[Parameter(Mandatory = $false,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Position = 0)]
[Alias('ComputerName', 'Computer')]
[string]
$Name = $env:COMPUTERNAME
)
Process
{
Write-Verbose "Running query.exe against $Name."
$Users = query user /server:$Name 2>&1
if ($Users -like "*No User exists*")
{
# Handle no user's found returned from query.
# Returned: 'No User exists for *'
Write-Error "There were no users found on $Name : $Users"
Write-Verbose "There were no users found on $Name."
}
elseif ($Users -like "*Error*")
{
# Handle errored returned by query.
# Returned: 'Error ...<message>...'
Write-Error "There was an error running query against $Name : $Users"
Write-Verbose "There was an error running query against $Name."
}
elseif ($Users -eq $null -and $ErrorActionPreference -eq 'SilentlyContinue')
{
# Handdle null output called by -ErrorAction.
Write-Verbose "Error action has supressed output from query.exe. Results were null."
}
else
{
Write-Verbose "Users found on $Name. Converting output from text."
# Conversion logic. Handles the fact that the sessionname column may be populated or not.
$Users = $Users | ForEach-Object {
(($_.trim() -replace ">" -replace "(?m)^([A-Za-z0-9]{3,})\s+(\d{1,2}\s+\w+)", '$1 none $2' -replace "\s{2,}", "," -replace "none", $null))
} | ConvertFrom-Csv
Write-Verbose "Generating output for $($Users.Count) users connected to $Name."
# Output objects.
foreach ($User in $Users)
{
Write-Verbose $User
if ($VerbosePreference -eq 'Continue')
{
# Add '| Out-Host' if -Verbose is tripped.
[PSCustomObject]@{
ComputerName = $Name
Username = $User.USERNAME
SessionState = $User.STATE.Replace("Disc", "Disconnected")
SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "")
IdleTime = $User.'IDLE TIME'
ID = $User.ID
LogonTime =$User.'Logon Time'
} | Out-Host
}
else
{
# Standard output.
[PSCustomObject]@{
ComputerName = $Name
Username = $User.USERNAME
SessionState = $User.STATE.Replace("Disc", "Disconnected")
SessionType = $($User.SESSIONNAME -Replace '#', '' -Replace "[0-9]+", "")
IdleTime = $User.'IDLE TIME'
LogonTime = $User.'Logon Time'
ID = $User.ID
}
}
}
}
}
}
$Servers = Get-Content 'H:\demo\computernames.txt'
$Queries = foreach ($Server in $Servers) {
#Query each server that pings, save it in a variable for reuse
if (Test-Connection $Server -Count 1 -Quiet) {
Convert-QueryToObjects $Server -ErrorAction SilentlyContinue
}
}
#Open servers are ones that responded to the query.
$Queries |
Select-Object -ExpandProperty ComputerName -Unique |
Out-File 'H:\demo\session\openservers.txt'
#Use the saved query information, filter with Where-Object, loop over to disconnect.
$Queries |
Where-Object { ($_.SessionState -eq 'Disconnected') -or (($_.IdleTime -like "*:*") -and ($_.IdleTime -gt "00:59"))} |
ForEach-Object {
Disconnect-LoggedOnUser -ComputerName $_.ComputerName -Id $_.ID -Verbose
}
Upvotes: 0
Views: 1740
Reputation: 10034
The issue is that H:\WindowsPowerShell\Get-LoggedOnUser.ps1 -ComputerName $Server| Disconnect-LoggedOnUser -Verbose
isn't filtered with Where-Object
. So you need to save the information of which users sessions need to be disconnected, then use that filtered information to disconnect.
Here's one way to approach it, comments inline.
$Servers = Get-Content 'H:\demo\computernames.txt'
$Queries = foreach ($Server in $Servers) {
#Query each server that pings, save it in a variable for reuse
if (Test-Connection $Server -Count 1 -Quiet) {
Convert-QueryToObjects $Server -ErrorAction SilentlyContinue
}
}
#Open servers are ones that responded to the query.
$Queries |
Select-Object -ExpandProperty ComputerName -Unique |
Out-File 'H:\demo\session\openservers.txt'
#Use the saved query information, filter with Where-Object, loop over to disconnect.
$Queries |
Where-Object { ($_.SessionState -eq 'Disconnected') -or (($_.IdleTime -like "*:*") -and ($_.IdleTime -gt "00:59"))} |
ForEachObject {
Disconnect-LoggedOnUser -ComputerName $_.ComputerName -Id $_.ID -Verbose
}
Upvotes: 2