PowerShellを使用してWindowsユーザーをリモートからログオフ

2月 03, 2019 セキュリティとコンプライアンス, MOVEit

エンドユーザーがずっと自分のコンピュータにログインしている場合、必要があれば簡単にリモートからエンドユーザーをログオフすることができます。メンテナンスをしようとしているときなどには、知っておくと特に便利です。

長期間ずっと自分のコンピュータにログインしたままのエンドユーザーがときどきいます。メンテナンスを行うとき、エンドユーザーはログアウトする必要がありますが、事前に通知してもログアウトしていないユーザーがいます。ログインしたままアイドル状態になっていることもあります。幸いなことに、他のコンピュータからリモートでエンドユーザーをログオフさせる方法があります。

PowerShell を使って、リモートの Windows コンピュータにアクセスし、誰かがログインしているかどうかを確認し、ログインしている場合はログオフさせるスクリプトを作成できます。全ユーザーをログオフさせることもできます。

まずどのユーザーがリモートコンピュータにログインしているかをチェックするところから始めましょう。いくつかの方法がありますが、ここでは quser コマンドを使います。これは PowerShell のコマンドではありませんが、PowerShell 内から簡単に使用できます。

Windows コンピュータ上でローカルに実行して、このコマンドがどう機能するかを確認できます。

PS> quser
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
>administrator         console             1  Active      none   9/22/2018 11:04 AM

出力された文字列は PowerShell で解析できるので、あまり気にする必要はありません。

quser コマンドは、/server スイッチを使用してリモートコンピュータにクエリできますが、PowerShell Remoting が使えるので、リモート処理は PowerShell で行い、リモートコンピュータ上で quser を実行します。

PS> Invoke-Command -ComputerName 'REMOTECOMPUTER' -ScriptBlock { quser }
 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
 abertram              rdp-tcp#7           2  Active          7  9/26/2018 4:57 PM

ログインしているユーザーを見つける方法がわかったので、今度はユーザーをログオフする方法を考えましょう。それには logoff コマンドが利用できます。logoff コマンドも PowerShell のコマンドではありませんが、簡単にスクリプトから呼び出せます。

上の例では、セッション2で 'abertram' がリモートコンピュータにログインしています。セッションIDを引数に入れてlogoff コマンドを使えば、簡単にユーザーをログオフできます。

PS> Invoke-Command -ComputerName 'REMOTECOMPUTER' -ScriptBlock { logoff 2 }

リモートコンピュータでもう一度 quser を実行すると、リモートコンピュータには誰もログインしておらず、セッション2がログオフされたことがわかります。

PS> Invoke-Command -ComputerName 'REMOTECOMPUTER' -ScriptBlock {quser}
No User exists for *
    + CategoryInfo          : NotSpecified: (No User exists for *:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
    + PSComputerName        : REMOTECOMPUTER

セッションIDではなくユーザー名を指定して、ユーザーアカウントをログオフするには、2つのコマンドを1つにまとめます。次のように、quser を実行し、アウトプットをユーザー名でフィルタリングし、そのアウトプットを解析してセッションIDを獲得して、それを logoff コマンドに送るスクリプトブロックを作成します。

$scriptBlock = {
    $ErrorActionPreference = 'Stop'

    try {
        ## Find all sessions matching the specified username
        $sessions = quser | Where-Object {$_ -match 'abertram'}
        ## Parse the session IDs from the output
        $sessionIds = ($sessions -split ' +')[2]
        Write-Host "Found $(@($sessionIds).Count) user login(s) on computer."
        ## Loop through each session ID and pass each to the logoff command
        $sessionIds | ForEach-Object {
            Write-Host "Logging off session id [$($_)]..."
            logoff $_
        }
    } catch {
        if ($_.Exception.Message -match 'No user exists') {
            Write-Host "The user is not logged in."
        } else {
            throw $_.Exception.Message
        }
    }
}

## Run the scriptblock's code on the remote computer
PS> Invoke-Command -ComputerName REMOTECOMPUTER -ScriptBlock $scriptBlock

Found 1 user login(s) on computer.
Logging off session id [rdp-tcp#10]...

Invoke-Command で、作成したスクリプトブロックをリモートコンピュータ上で実行すると、ログインしているユーザーを検出し、すぐにログオフします。

Adam Bertram

Adam Bertram is a 20-year veteran of IT. He’s currently an automation engineer, blogger, independent consultant, freelance writer, author, and trainer. Adam focuses on DevOps, system management, and automation technologies as well as various cloud platforms. He is a Microsoft Cloud and Datacenter Management MVP and efficiency nerd that enjoys teaching others a better way to leverage automation.

Read next 何百ものサーバーからの Windows イベントログを検索する方法