Powershellコマンドを作成して、ユーザーをリモートでログオフしようとしています。時々セッションをロックする非常に不安定なプログラムを備えたターミナルサーバーがあります。ユーザーをリモートでログオフする必要がありますが、スクリプトを実行した人をログオフするPowershellステートメントを記述しようとしています。私はグーグルで調べて、このコマンドを見つけました:
Invoke-Command -ComputerName MyServer -Command {shutdown -l}
ただし、コマンドは「不正な関数」を返します。 Get-Processなど、かっこ内の他のコマンドを正常に実行できます。
私は、それをユーザーがサーバーからログオフするために実行できるスクリプトにそれを入れることを考えています(ロックすると、GUIを介してそれを行うためにスタートメニューまたはALT + CTRL + ENDにアクセスできないため)。
フローは次のようになります。BobはRDP経由でMyServerにログインしますが、セッションはフリーズします。ローカルデスクトップで、彼はMyServerでセッションをログオフするMyScript(上記と同様のコマンドを含む)を実行できます。
おそらく驚くべきことに、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.
セッションIDは、qwinsta
(query session
)またはquser
(query user
)コマンド( here を参照):
$server = 'MyServer'
$username = $env:USERNAME
$session = ((quser /server:$server | ? { $_ -match $username }) -split ' +')[2]
logoff $session /server:$server
誰かがそんなに傾いているなら、普通の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
リモートまたはローカルでユーザーをログアウトするための優れたスクリプトソリューションを次に示します。セッション情報を取得するために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を指定します。このスクリプトを使用して、自動化プロセスがいくつかのフォルダーを移動しようとする前にユーザーをキックします。 「使用中のファイル」エラーを防止します。別の注意点として、このスクリプトは管理者ユーザーとして実行する必要があります。そうしないと、ログアウトしようとしてアクセスを拒否される可能性があります。お役に立てれば!
これはオールドスクールであり、PowerShellより前のものですが、YEARSのqwinsta/rwinstaコンボを使用して、古いRDPセッションをリモートでログオフしました。少なくともWindowsに組み込まれていますXP and forward(おそらく以前)
セッションIDを決定します。
qwinsta /SERVER:<NAME>
問題のセッションを削除します。
rwinsta <SESSION_ID> /SERVER:<NAME>
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(%)のみを使用しようとすると、1人のユーザーのみがログオフされます。しかし、foreachとパイプのこの組み合わせを使用すると:
| %{$ _ |コマンド}
期待どおりに動作します。
追伸Admとして実行します。
Terminal Services PowerShell Module を試してください:
Get-TSSession -ComputerName comp1 -UserName user1 | Stop-TSSession -Force
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 {}
}
マシンからすべてのユーザーをログオフします。
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の要素があるため、これを行う必要がありますセッション私のコードはより簡単で、より速く動作するはずです。
$logon_sessions = get-process -includeusername | Select-Object -Unique -Property UserName, si | ? { $_ -match "server" -and $_ -notmatch "admin" }
foreach ($id in $logon_sessions.si) {
logoff $id
}
以下のスクリプトは、ユーザーがlogoffコマンドをリモートで実行するためのアクセス権を持っている限り、アクティブセッションと切断セッションの両方で適切に機能します。必要なのは、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領域にいるので、適切な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