web-dev-qa-db-ja.com

PowerShellのリモートセッションからのログオフ

Powershellコマンドを作成して、ユーザーをリモートでログオフしようとしています。時々セッションをロックする非常に不安定なプログラムを備えたターミナルサーバーがあります。ユーザーをリモートでログオフする必要がありますが、スクリプトを実行した人をログオフするPowershellステートメントを記述しようとしています。私はグーグルで調べて、このコマンドを見つけました:

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

ただし、コマンドは「不正な関数」を返します。 Get-Processなど、かっこ内の他のコマンドを正常に実行できます。

私は、それをユーザーがサーバーからログオフするために実行できるスクリプトにそれを入れることを考えています(ロックすると、GUIを介してそれを行うためにスタートメニューまたはALT + CTRL + ENDにアクセスできないため)。

フローは次のようになります。BobはRDP経由でMyServerにログインしますが、セッションはフリーズします。ローカルデスクトップで、彼はMyServerでセッションをログオフするMyScript(上記と同様のコマンドを含む)を実行できます。

29
jlacroix

おそらく驚くべきことに、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は、qwinstaquery session)またはquserquery user)コマンド( here を参照):

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

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

logoff $session /server:$server
45
Ansgar Wiechers

誰かがそんなに傾いているなら、普通の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
12
user4317867

リモートまたはローカルでユーザーをログアウトするための優れたスクリプトソリューションを次に示します。セッション情報を取得するために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を指定します。このスクリプトを使用して、自動化プロセスがいくつかのフォルダーを移動しようとする前にユーザーをキックします。 「使用中のファイル」エラーを防止します。別の注意点として、このスクリプトは管理者ユーザーとして実行する必要があります。そうしないと、ログアウトしようとしてアクセスを拒否される可能性があります。お役に立てれば!

12
Jason Slobotski

これはオールドスクールであり、PowerShellより前のものですが、YEARSのqwinsta/rwinstaコンボを使用して、古いRDPセッションをリモートでログオフしました。少なくともWindowsに組み込まれていますXP and forward(おそらく以前)

セッションIDを決定します。

qwinsta /SERVER:<NAME>

問題のセッションを削除します。

rwinsta <SESSION_ID> /SERVER:<NAME>
7
Joshua McKinnon

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として実行します。

4
Gauss

Terminal Services PowerShell Module を試してください:

Get-TSSession -ComputerName comp1 -UserName user1 | Stop-TSSession -Force
4
Shay Levy

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 {}
    }
3
O.C.

マシンからすべてのユーザーをログオフします。

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の要素があるため、これを行う必要がありますセッション
2
cmcginty

私のコードはより簡単で、より速く動作するはずです。

    $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!"

いくつかのサンプル出力。アクティブなセッションの場合: enter image description here

切断されたセッションの場合: enter image description here

セッションが見つからなかった場合: enter image description here このソリューションもチェックアウトして、すべてのADサーバーにユーザー名を照会し、切断されたセッションのみをログオフします。また、スクリプトは、サーバーへの接続中またはサーバーへのクエリ中にエラーが発生したかどうかを通知します。

切断されたRDPセッションを検出し、同時にログオフするPowerShell

0
LT-

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

それをさらに一歩進めて、私のブログで非常にきれいなオブジェクトを提供します。

0
VertigoRay