32

我正在尝试制定一个 Powershell 命令来远程注销用户。我们有一个终端服务器,它的程序非常不稳定,有时会锁定会话。我们必须远程注销用户,但我正在尝试编写一个 Powershell 语句,该语句将注销运行脚本的人。我用谷歌搜索了一下,发现了这个命令:

Invoke-Command -ComputerName MyServer -Command {shutdown -l}

但是,该命令返回“不正确的功能”。我可以在括号中成功运行其他命令,例如Get-Process。

我的想法是把它放到一个脚本中,用户可以运行该脚本来注销服务器(因为当它锁定时,他们无法访问开始菜单或 ALT+CTRL+END 来通过 GUI 执行此操作)。

流程是这样的:Bob 通过 RDP 登录到 MyServer,但他的会话冻结。在他的本地桌面上,他可以运行 MyScript(包含类似于上面的命令),这将注销他在 MyServer 上的会话。

4

11 回答 11

50

logoff也许令人惊讶的是,您可以使用该命令注销用户。

C:\> logoff /?
Terminates a session.

LOGOFF [sessionname | sessionid] [/SERVER:servername] [/V] [/VM]

  sessionname         The name of the session.
  sessionid           The ID of the session.
  /SERVER:servername  Specifies the Remote Desktop server containing the user
                      session to log off (default is current).
  /V                  Displays information about the actions performed.
  /VM                 Logs off a session on server or within virtual machine.
                      The unique ID of the session needs to be specified.

可以使用qwinsta( query session) 或quser( query user) 命令确定会话 ID(参见此处):

$server   = 'MyServer'
$username = $env:USERNAME

$session = ((quser /server:$server | ? { $_ -match $username }) -split ' +')[2]

logoff $session /server:$server
于 2013-08-12T17:52:14.623 回答
15

这是一个很棒的脚本解决方案,用于远程或本地注销人员。我正在使用 qwinsta 获取会话信息并根据给定的输出构建一个数组。这使得遍历每个条目并仅注销实际用户变得非常容易,而不是系统或 RDP 侦听器本身,这通常只会引发访问被拒绝错误。

$serverName = "Name of server here OR localhost"
$sessions = qwinsta /server $serverName| ?{ $_ -notmatch '^ SESSIONNAME' } | %{
$item = "" | Select "Active", "SessionName", "Username", "Id", "State", "Type", "Device"
$item.Active = $_.Substring(0,1) -match '>'
$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.Type = $_.Substring(56,12).Trim()
$item.Device = $_.Substring(68).Trim()
$item
} 

foreach ($session in $sessions){
    if ($session.Username -ne "" -or $session.Username.Length -gt 1){
        logoff /server $serverName $session.Id
    }
}

在此脚本的第一行中,如果在本地运行,则为 $serverName 提供适当的值或 localhost。我使用此脚本在自动过程尝试移动某些文件夹之前踢出用户。为我防止“文件正在使用”错误。另请注意,此脚本必须以管理员用户身份运行,否则您可能会在尝试注销某人时被拒绝访问。希望这可以帮助!

于 2016-03-07T16:09:43.810 回答
14

添加简单的 DOS 命令,如果有人愿意的话。是的,这仍然适用于 Win 8 和 Server 2008 + Server 2012。

Query session /server:Server100

将返回:

SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
rdp-tcp#0         Bob                       3  Active  rdpwd
rdp-tcp#5         Jim                       9  Active  rdpwd
rdp-tcp                                 65536  Listen

要注销会话,请使用:

Reset session 3 /server:Server100
于 2015-10-04T16:26:26.613 回答
7

这是老式的并且早于 PowerShell,但我已经使用 qwinsta / rwinsta 组合多年来远程注销过时的 RDP 会话。它至少内置于 Windows XP 及更高版本(可能更早)

确定会话 ID:

qwinsta /SERVER:<NAME>

删除有问题的会话:

rwinsta <SESSION_ID> /SERVER:<NAME>
于 2013-08-12T18:32:00.963 回答
5

You can use Invoke-RDUserLogoff

An example logging off Active Directory users of a specific Organizational Unit:

$users = Get-ADUser -filter * -SearchBase "ou=YOUR_OU_NAME,dc=contoso,dc=com"

Get-RDUserSession | where { $users.sAMAccountName -contains $_.UserName } | % { $_ | Invoke-RDUserLogoff -Force }

At the end of the pipe, if you try to use only foreach (%), it will log off only one user. But using this combination of foreach and pipe:

| % { $_ | command }

will work as expected.

Ps. Run as Adm.

于 2014-05-14T21:48:44.683 回答
4

尝试终端服务 PowerShell 模块

Get-TSSession -ComputerName comp1 -UserName user1 | Stop-TSSession -Force
于 2013-08-12T18:18:51.120 回答
3

我通过执行以下操作修改了凯西对仅注销断开连接的会话的回答:

   foreach($Server in $Servers) {
    try {
        query user /server:$Server 2>&1 | select -skip 1 | ? {($_ -split "\s+")[-5] -eq 'Disc'} | % {logoff ($_ -split "\s+")[-6] /server:$Server /V}
    }
    catch {}
    }
于 2015-06-25T13:49:27.063 回答
2

从机器上注销所有用户:

try {
   query user /server:$SERVER 2>&1 | select -skip 1 | foreach {
     logoff ($_ -split "\s+")[-6] /server:$SERVER
   }
}
catch {}

细节:

  • try/在catch服务器上没有用户时使用,并且query返回错误。但是,如果您不介意看到错误字符串,您可以删除该2>&1部分并删除try/catch
  • select -skip 1删除标题行
  • 内部foreach注销每个用户
  • ($_ -split "\s+")将字符串拆分为仅包含文本项的数组
  • [-6]index 获取会话 ID 并且是从数组倒数算起的第 6 个字符串,您需要这样做,因为query输出将包含 8 个或 9 个元素,具体取决于用户是从终端会话连接还是断开连接
于 2014-06-06T02:32:19.437 回答
1

我相信我的代码会更容易并且运行得更快。

    $logon_sessions = get-process -includeusername | Select-Object -Unique -Property UserName, si | ? { $_ -match "server" -and $_ -notmatch "admin" }

    foreach ($id in $logon_sessions.si) {
        logoff $id
    }
于 2019-06-22T07:30:22.017 回答
0

这是我想出的。结合多个答案

#computer list below
$computers = (
'computer1.domain.local',
'computer2.domain.local'

)
 
foreach ($Computer in $computers) {

 Invoke-Command -ComputerName $Computer -ScriptBlock { 
  Write-Host '______  '$Env:Computername
  $usertocheck = 'SomeUserName'
$sessionID = ((quser | Where-Object { $_ -match $usertocheck }) -split ' +')[2]
 

If([string]::IsNullOrEmpty($sessionID)){            
    Write-Host -ForegroundColor Yellow  "User Not Found."           
} else {            
    write-host -ForegroundColor Green  'Logging off ' $usertocheck 'Session ID' $sessionID
    logoff $sessionID    
}

 }
 }
于 2020-07-23T03:31:36.577 回答
0

只要用户有权远程运行注销命令,下面的脚本将适用于活动和断开连接的会话。您所要做的就是从第 4 行的“YourServerName”更改服务器名称。

param (
    $queryResults = $null,
    [string]$UserName = $env:USERNAME,
    [string]$ServerName = "YourServerName"
)


if (Test-Connection $ServerName -Count 1 -Quiet) {  
    Write-Host "`n`n`n$ServerName is online!" -BackgroundColor Green -ForegroundColor Black


    Write-Host ("`nQuerying Server: `"$ServerName`" for disconnected sessions under UserName: `"" + $UserName.ToUpper() + "`"...") -BackgroundColor Gray -ForegroundColor Black

        query user $UserName /server:$ServerName 2>&1 | foreach {  

            if ($_ -match "Active") {
                Write-Host "Active Sessions"
                $queryResults = ("`n$ServerName," + (($_.trim() -replace ' {2,}', ','))) | ConvertFrom-Csv -Delimiter "," -Header "ServerName","UserName","SessionName","SessionID","CurrentState","IdealTime","LogonTime"


                $queryResults | ft
                Write-Host "Starting logoff procedure..." -BackgroundColor Gray -ForegroundColor Black

                $queryResults | foreach {
                    $Sessionl = $_.SessionID
                    $Serverl = $_.ServerName
                    Write-Host "Logging off"$_.username"from $serverl..." -ForegroundColor black -BackgroundColor Gray
                    sleep 2
                    logoff $Sessionl /server:$Serverl /v

                }


            }                
            elseif ($_ -match "Disc") {
                Write-Host "Disconnected Sessions"
                $queryResults = ("`n$ServerName," + (($_.trim() -replace ' {2,}', ','))) |  ConvertFrom-Csv -Delimiter "," -Header "ServerName","UserName","SessionID","CurrentState","IdealTime","LogonTime"

                $queryResults | ft
                Write-Host "Starting logoff procedure..." -BackgroundColor Gray -ForegroundColor Black

                $queryResults | foreach {
                    $Sessionl = $_.SessionID
                    $Serverl = $_.ServerName
                    Write-Host "Logging off"$_.username"from $serverl..."
                    sleep 2
                    logoff $Sessionl /server:$Serverl /v

                }
            }
            elseif ($_ -match "The RPC server is unavailable") {

                Write-Host "Unable to query the $ServerName, check for firewall settings on $ServerName!" -ForegroundColor White -BackgroundColor Red
            }
            elseif ($_ -match "No User exists for") {Write-Host "No user session exists"}

    }
}
else {

    Write-Host "`n`n`n$ServerName is Offline!" -BackgroundColor red -ForegroundColor white
    Write-Host "Error: Unable to connect to $ServerName!" -BackgroundColor red -ForegroundColor white
    Write-Host "Either the $ServerName is down or check for firewall settings on server $ServerName!" -BackgroundColor Yellow -ForegroundColor black
}





Read-Host "`n`nScript execution finished, press enter to exit!"

一些示例输出。对于活动会话: 在此处输入图像描述

对于断开连接的会话: 在此处输入图像描述

如果未找到会话: 在此处输入图像描述 请查看此解决方案,以查询所有 AD 服务器以获取您的用户名并仅注销已断开连接的会话。该脚本还将告诉您连接或查询服务器是否出错。

Powershell找出断开的RDP会话并同时注销

于 2018-08-18T02:56:09.867 回答