我正在尝试制定一个Powershell命令来远程注销用户。我们有一个终端服务器,程序非常不稳定,有时会锁定会话。我们必须远程注销用户,但我正在尝试编写一个Powershell语句,该语句将注销运行该脚本的人员。我用Google搜索,发现了这个命令:
Invoke-Command -ComputerName MyServer -Command {shutdown -l}
但是,该命令返回“错误的功能”。我可以在括号中成功运行其他命令,例如Get-Process。
我的想法是让我把它放到一个脚本中,用户可以运行该脚本将自己从服务器上注销(因为当它锁定时,他们无法访问开始菜单或ALT + CTRL + END通过GUI执行此操作)
流程将是这样的: Bob通过RDP登录MyServer,但他的会话冻结了。在他的本地桌面上,他可以运行MyScript(包含类似于上面的命令),这将在MyServer上注销他的会话。
答案 0 :(得分:45)
也许令人惊讶的是,您可以使用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(请参阅here):
$server = 'MyServer'
$username = $env:USERNAME
$session = ((quser /server:$server | ? { $_ -match $username }) -split ' +')[2]
logoff $session /server:$server
答案 1 :(得分:12)
这是一个很棒的脚本解决方案,可以远程或本地记录人员。我正在使用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。在自动进程尝试移动某些文件夹之前,我使用此脚本来踢用户。为我防止“文件使用中”错误。另请注意,此脚本必须以管理员用户身份运行,否则您可能会被拒绝尝试将某人记录下来。希望这有帮助!
答案 2 :(得分:11)
添加纯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
答案 3 :(得分:7)
这是oldschool并且早于PowerShell,但是我使用qwinsta / rwinsta组合为YEARS远程注销陈旧的RDP会话。它内置于至少Windows XP和前进(可能更早)
确定会话ID:
qwinsta /SERVER:<NAME>
删除有问题的会话:
rwinsta <SESSION_ID> /SERVER:<NAME>
答案 4 :(得分:4)
试试Terminal Services PowerShell Module:
Get-TSSession -ComputerName comp1 -UserName user1 | Stop-TSSession -Force
答案 5 :(得分:4)
您可以使用 Invoke-RDUserLogoff
注销特定组织单位的Active Directory用户的示例:
$users = Get-ADUser -filter * -SearchBase "ou=YOUR_OU_NAME,dc=contoso,dc=com"
Get-RDUserSession | where { $users.sAMAccountName -contains $_.UserName } | % { $_ | Invoke-RDUserLogoff -Force }
在管道的末尾,如果您尝试仅使用foreach(%),它将仅注销一个用户。但是使用foreach和pipe的这种组合:
| %{$ _ |命令}
将按预期工作。
聚苯乙烯。作为Adm运行。
答案 6 :(得分:3)
我已修改Casey's answer以仅通过执行以下操作来注销已断开连接的会话:
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 {}
}
答案 7 :(得分: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]
索引获取会话ID,并且是从数组的反向计数的第6个字符串,您需要这样做,因为query
输出将具有8或9个元素,具体取决于用户是否连接或与终端会话断开连接答案 8 :(得分:0)
由于我们位于PowerShell区域,因此如果我们可以返回正确的PowerShell对象,则特别有用...
出于个人的简洁性,我个人喜欢这种解析方法:
((quser) -replace '^>', '') -replace '\s{2,}', ',' | ConvertFrom-Csv
注意: 这不能解决断开连接的用户,但是如果您只想快速获取用户列表,效果很好并且不在乎其余信息。我只想要一个列表,不在乎它们当前是否断开连接。
如果您确实关心其余数据,则稍微复杂一点:
(((quser) -replace '^>', '') -replace '\s{2,}', ',').Trim() | ForEach-Object {
if ($_.Split(',').Count -eq 5) {
Write-Output ($_ -replace '(^[^,]+)', '$1,')
} else {
Write-Output $_
}
} | ConvertFrom-Csv
I take it a step farther and give you a very clean object on my blog.
答案 9 :(得分:0)
下面的脚本对于活动会话和断开连接的会话都适用,只要用户可以远程运行注销命令即可。您所要做的就是从第四行的“ 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 to find out disconnected RDP session and log off at the same time
答案 10 :(得分:0)
我确信我的代码会更容易并且运行更快。
$logon_sessions = get-process -includeusername | Select-Object -Unique -Property UserName, si | ? { $_ -match "server" -and $_ -notmatch "admin" }
foreach ($id in $logon_sessions.si) {
logoff $id
}
答案 11 :(得分: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
}
}
}