使用会话ID断开用户与服务器的连接

时间:2017-07-10 18:11:08

标签: powershell powershell-v2.0 powershell-v3.0

我编写了一个脚本,用于优化断开连接或空闲时间超过60分钟的用户。我已经设置了这些参数,但过滤器运行良好;该脚本不是断开该服务器中的特定用户,而是将服务器断开连接为整体

我正在使用另外两个函数,其中一个我直接添加到脚本中。另一个来自Get-LoggedOnUser.ps1 Disconnect-LoggedOnUser和Get-LoggedOnUser旨在协同工作。我保留了注销脚本的说明。我已将此完整脚本包含在此GitHub gist

非常感谢任何帮助或建议! 以下所有相关代码:

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 
    }

1 个答案:

答案 0 :(得分:2)

问题是H:\WindowsPowerShell\Get-LoggedOnUser.ps1 -ComputerName $Server| Disconnect-LoggedOnUser -Verbose未使用Where-Object进行过滤。因此,您需要保存需要断开连接的用户会话的信息,然后使用该过滤后的信息断开连接。

这是一种接近它的方法,内联评论。

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