Удаленный сеанс удаленного доступа Powershell
Я пытаюсь сформулировать команду Powershell для удаленного выхода из системы. У нас есть терминальный сервер с очень неустойчивой программой, которая иногда блокирует сеансы. Мы должны удаленно выходить из системы, но я пытаюсь написать оператор Powershell, который выйдет из системы, который запускает скрипт. Я разобрался и нашел эту команду:
Invoke-Command -ComputerName MyServer -Command {shutdown -l}
Однако команда возвращает «неправильную функцию». Я могу успешно запускать другие команды в скобках, например Get-Process.
Идея заключается в том, чтобы я включил ее в сценарий, который пользователи могут запускать для выхода из сервера (поскольку, когда он блокируется, они не могут получить доступ к меню «Пуск» или ALT + CTRL + END, чтобы сделать это через графический интерфейс).
Поток будет следующим: Боб входит в MyServer через RDP, но его сеанс замерзает. На своем локальном рабочем столе он может запускать MyScript (содержащий команду, аналогичную приведенной выше), которая выйдет из сеанса на MyServer.
Возможно, вы можете выйти из системы с помощью команды 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
) (см. Здесь ):
$server = 'MyServer' $username = $env:USERNAME $session = ((quser /server:$server | ? { $_ -match $username }) -split ' +')[2] logoff $session /server:$server
Вот отличное скриптовое решение для удаленного доступа или локализации пользователей. Я использую 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, если он выполняется локально. Я использую этот скрипт для загрузки пользователей, прежде чем автоматический процесс попытается переместить некоторые папки. Предотвращает ошибки «файл в использовании» для меня. Еще одно замечание: этот скрипт должен запускаться как пользователь-администратор, иначе вы можете получить доступ к нему, отказавшему в попытке зарегистрировать кого-то. Надеюсь это поможет!
Добавление простых команд 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
Это oldschool и предшествует PowerShell, но я использовал компиляцию qwinsta / rwinsta для YEARS для удаленного выхода из устаревших сеансов RDP. Он встроен, по крайней мере, в Windows XP и вперёд (возможно, раньше)
Определите идентификатор сеанса:
qwinsta /SERVER:
Удалите сеанс, о котором идет речь:
rwinsta /SERVER:
Попробуйте модуль служб терминалов PowerShell :
Get-TSSession -ComputerName comp1 -UserName user1 | Stop-TSSession -Force
Вы можете использовать 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:
| % {$ _ | команда}
будет работать должным образом.
Ps. Выполнить как ад.
Я изменил ответ Кейси только на отключенные сеансы выхода из системы, выполнив следующие действия:
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 {} }
Выйдите из системы всеми пользователями:
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 получает идентификатор сеанса и является 6-м строковым подсчетом с обратной стороны массива, вам нужно сделать это, потому что выводquery
будет содержать 8 или 9 элементов в зависимости от того, подключены ли пользователи или отключены от сеанса терминала
Поскольку мы находимся в области PowerShell, это очень полезно, если мы можем вернуть правильный объект PowerShell …
Мне лично нравится этот метод parsingа, для терпения:
((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
Я делаю шаг дальше и даю вам очень чистый объект в своем блоге.
Ниже сценария будет хорошо работать как для активных, так и для отключенных сеансов, если пользователь имеет доступ к удаленному запуску команды logoff. Все, что вам нужно сделать, это изменить имя сервера из «YourServerName» на 4-й строке.
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 и выйти из системы одновременно