PowerShellを使用してリモートでログオンしたユーザーを見つけるためのより良い方法
ログオンしたユーザーを取得するにはさまざまな方法がありますが、私はお気に入りを持っています! 使用してqwinsta
、唯一の問題は、文字列を返し、PowerShellがオブジェクトを好むことです:(しかし、決して恐れることはありません! それを直せるQwinsta
前提条件
私は最初にqwinsta
を使い始めたときにエラー5アクセス拒否の問題に遭遇しました、そのためのレジストリ修正があります(StackOverflowに感謝:
"AllowRemoteRPC"=dword:00000001
これはPowerShellのブログなので、ここでは、リモートコンピュータ上で作業する可能性が高いので、リモートコンピュータに追加するためのPowerShell構文です。
$ComputerName = 'Computer' #replace with the computer name$LMtype = ::LocalMachine$LMkey = "SYSTEM\CurrentControlSet\Control\Terminal Server"$LMRegKey = ::OpenRemoteBaseKey($LMtype,$ComputerName)$regKey = $LMRegKey.OpenSubKey($LMkey,$true)If($regKey.GetValue("AllowRemoteRPC") -ne 1){ $regKey.SetValue("AllowRemoteRPC",1) Start-Sleep -Seconds 1}$regKey.Dispose()$LMRegKey.Dispose()
構文
qwinstaの構文はかなり簡単です:
qwinsta /server:ServerName
そして、出力はむしろunmenacingに見えます:
SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console Anthony 1 Active rdp-tcp 65536 Listen
唯一の問題は、Rdsサーバーを見ていた場合、PowerShellで文字列をフィルタリングする簡単な方法がないことです。 だからあなたは次のようなことをすることができませんでした:
qwinsta /server:RDSServer | Where-Object USERNAME -like "Anth*"
しかし、我々はそれを修正することができます! Qwinstaをラップして、その出力をオブジェクト化できるようにしましょう!
ラッピングqwinsta
ここでPowerShell関数を作成します。
その値の文字列を絞り出す
私たちが得るすべてのパラメータのもののほかに、私たちがやる最初のコアのことは、出力を変数に向けることです:
$result = qwinsta /server:$ComputerName
今$result
ちょうど前からの出力のようになりますが、それは文字列配列(string
)としてフォーマットされます。 私たちは、もちろん、それを検証することができますGet-Member
:
($result | Get-Member).TypeName
だから、次のことは、我々が望むだけの情報を取得することです。 私はヘッダーを必要としないので、最初の行をスキップしてforループを決めました:
ForEach($line in $result)
各行について、各値は何で区切られていますか? スペース! だから我々は使用することができます。文字列のSplit()メソッドと各スペースで分割します。 唯一の注意点は、複数のスペースを分割してnull値を取得できるため、各分割で値をテストする必要があることです。
$tmp = $line.split(" ") | ?{$_.length -gt 0}
注意すべきことの1つは、qwinsta
からの出力はfixed-widthであり、値の長さに関係なく幅が変更されないことです。 私達はそれを利用し、私達の利点にある索引を使用してもいい。
最初に行うことは、実際にどの行にユーザーが含まれているかを判断することです。 文字を数えて、ユーザー名の値が19番目の文字で始まることがわかります(最初の文字は実際にはスペースですが、慎重に見てください)。 したがって、19番目の文字が空でない場合、ユーザーがいます。
If(($line -ne " "))
私がqwinsta
でテストして気づいた次のことは、セッションが’Active’状態にある場合にのみSessionNameプロパティが値を持つことです。 そのため、状態が「アクティブ」であるかどうかを確認する必要もあります。’
If($line -eq "A")
それが’Active’の場合、$tmp
変数は異なる量の値を持ちます。
アクティブ:
#raw rdp-tcp#0 anthony 2 Active #$tmp variable (split)rdp-tcp#0anthony2Active
アクティブではない:
#raw anthony 2 Disc #$tmp variable (split)anthony2Disc
値を使用可能なオブジェクトに変換する
すべての値を理解したら、私のお気に入りの新しいPSObjectを作成できます! Powershellv5を使用している場合は、{}
型アクセラレータ(x)を使用できますが、最終的な互換性のためにここでNew-Object
コマンドレットを使用します。
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp}
この場合、セッションがアクティブであることがわかっているため、$tmp
の最初の文字列はセッション名であり、残りのプロパティが順番にあります。 ‘Type’または’SessionName’が空に戻る可能性があります。
状態が’アクティブ’でない場合は、それを次のように切り替えます:
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null}
最終製品
これは関数の作成に関する投稿ではないので、他の構文をスキップして、私が書いた最終的な関数を紹介します。 これには、エキサイティングなものに入る前に、接続性や管理者権限をチェックするなどのベストプラクティスが含まれています。
Function Get-ActiveSessions{ Param( $Name , $Quiet ) Begin{ $return = @() } Process{ If(!(Test-Connection $Name -Quiet -Count 1)){ Write-Error -Message "Unable to contact $Name. Please verify its network connectivity and try again." -Category ObjectNotFound -TargetObject $Name Return } If(((::GetCurrent()).groups -match "S-1-5-32-544")){ #check if user is admin, otherwise no registry work can be done #the following registry key is necessary to avoid the error 5 access is denied error $LMtype = ::LocalMachine $LMkey = "SYSTEM\CurrentControlSet\Control\Terminal Server" $LMRegKey = ::OpenRemoteBaseKey($LMtype,$Name) $regKey = $LMRegKey.OpenSubKey($LMkey,$true) If($regKey.GetValue("AllowRemoteRPC") -ne 1){ $regKey.SetValue("AllowRemoteRPC",1) Start-Sleep -Seconds 1 } $regKey.Dispose() $LMRegKey.Dispose() } $result = qwinsta /server:$Name If($result){ ForEach($line in $result){ #avoiding the line 0, don't want the headers $tmp = $line.split(" ") | ?{$_.length -gt 0} If(($line -ne " ")){ #username starts at char 19 If($line -eq "A"){ #means the session is active ("A" for active) $return += New-Object PSObject -Property @{ "ComputerName" = $Name "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp } }Else{ $return += New-Object PSObject -Property @{ "ComputerName" = $Name "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null } } } } }Else{ Write-Error "Unknown error, cannot retrieve logged on users" } } End{ If($return){ If($Quiet){ Return $true } Else{ Return $return } }Else{ If(!($Quiet)){ Write-Host "No active sessions." } Return $false } }}
Get-ActiveSessions
これは私のUtilities GitHub repoで見つけることができます。 これは私の最初の公開されたスクリプトです! 万歳! だから、それを使用する方法を上に行くことができます:
簡単な使用法
リモートまたはローカルコンピュータにログインしているユーザーを取得するには、次のように単純に使用します:
Get-ActiveSessions ComputerName
そして、これは次のようなものを返すはずです:
ID : 2SessionName :Type :UserName : anthonyComputerName : dc01State : Disc
そして、それを変数に渡して型名を見ると、PSCustomObject
が必要です。
$sessions = Get-ActiveSessions ComputerName($sessions | Get-Member).TypeNameSystem.Management.Automation.PSCustomObject
高度な使用法
ここでは、パイプライン入力を受け入れることができ、オブジェクトを出力することができます。 だから我々はGet-ActiveSessions
の前後に何かをすることができます。
特定のユーザーがログインしている環境内のすべてのサーバーを検索する場合はどうすればよいですか?
Get-ADComputer -Filter {OperatingSystem -like '*Server*'} | Get-ActiveSessions | Where-Object UserName -eq 'Anthony'
または、テキストファイルからコンピュータのリストを取得し、それらすべてにログインした一意のユーザーのリストを出力するのはどうですか?
get-content C:\temp\computers.txt | Get-ActiveSessions | Select-Object -Unique UserName -ExpandProperty UserName | Out-File C:\temp\users.txt
あなたはGet-ActiveSessions
の任意の有用な用途を思い付く場合は、コメント!
結論
うまくいけば、私は私のためにこのようなものを行うための関数を書くだろう理由のための感謝を持っています。 私は正直なところ、私は私の仕事を容易にするためにこれを使用した回数を数えることができませんでした。
とにかく、私はいくつかの注目すべき投稿、特にGet-ActiveSessions
のパートナー:Close-ActiveSessions
が登場しています。
ネタバレ:
Get-ActiveSessions Computer | Close-ActiveSessions
また、”PowerShellスクリプトのスケジュールされたタスクの作成”は、私はまだ画像を行っていないので、旅行になります!
Leave a Reply