【问题标题】:How to find amount of time mstsc is used and by whom?如何查找 mstsc 的使用时间以及由谁使用?
【发布时间】:2023-05-04 16:10:01
【问题描述】:

我们的团队地理位置分散,他们会使用远程桌面连接许多虚拟机。我想知道谁在访问远程桌面会话以及使用了多长时间。

我试着用 powershell 来做。我编写了一个脚本,用户将在其中使用 powershell 调用 mstsc。它将记录谁已登录以及何时登录。但我想知道有人从 mstsc 注销或断开 mstsc 的时间。有什么方法可以使用 powershell 在日志文件中捕获该信息。关闭 mstsc 时是否会触发任何事件?

【问题讨论】:

    标签: powershell powershell-2.0 rdp mstsc


    【解决方案1】:

    我写了一个 PowerShell 模块,PSTerminalServices (http://psterminalservices.codeplex.com),它建立在 Cassia 之上。 这是一个示例命令输出:

    PS> Get-TSSession | fl *
    
    IPAddress          :
    State              : Active
    ApplicationName    :
    Local              : False
    RemoteEndPoint     :
    InitialProgram     :
    WorkingDirectory   :
    ClientProtocolType : Console
    ClientProductId    : 0
    ClientHardwareId   : 0
    ClientDirectory    :
    ClientDisplay      : Cassia.Impl.ClientDisplay
    ClientBuildNumber  : 0
    Server             : Cassia.Impl.TerminalServer
    ClientIPAddress    :
    WindowStationName  : Console
    DomainName         : homelab
    UserAccount        : homelab\shay
    ClientName         :
    ConnectionState    : Active
    ConnectTime        : 12/15/2011 2:47:02 PM
    CurrentTime        : 12/23/2011 4:35:21 PM
    DisconnectTime     :
    LastInputTime      :
    LoginTime          : 12/15/2011 3:11:58 PM
    IdleTime           : 00:00:00
    SessionId          : 1
    UserName           : shay
    

    【讨论】:

    • 我经常使用这个模块(与 OP 需要它的原因基本相同,以了解我的 VM 的使用模式),我强烈推荐它。
    • @Shay Levy:我收到了这个错误。使用“0”参数调用“打开”的异常:“RPC 服务器不可用”。端口 445 已打开但仍在获取。
    • @Winfred:我可以知道你如何使用它吗?我的意思是,你会每天晚上用ip地址列表执行,看看今天机器是否被使用过吗?或者你如何确定使用模式?如果您希望我可以将其作为一个单独的问题提出。
    • 中间有防火墙吗?
    • 您能否验证目标上的 445 端口上是否有服务正在侦听?
    【解决方案2】:

    您可以使用Cassia 来获取 rdp 会话信息(可以定期记录到日志文件中)。

    这是一个如何在 Powershell 中使用 cassia 的简单示例:

    [reflection.assembly]::loadfile("d:\cassia.dll")
    $manager = new-object Cassia.TerminalServicesManager
    $server = $manager.GetRemoteServer("<name of your server>")
    $server.open()
    $server.getsessions()
    

    它将返回类似这样的内容(对于每个会话):

    ClientDisplay     : Cassia.Impl.ClientDisplay
    ClientBuildNumber : 0
    Server            : Cassia.Impl.TerminalServer
    ClientIPAddress   : 
    WindowStationName : 
    DomainName        : CONTOSO
    UserAccount       : CONTOSO\admin
    ClientName        : 
    ConnectionState   : Disconnected
    ConnectTime       : 22/12/2011 19:02:00
    CurrentTime       : 23/12/2011 9:00:42
    DisconnectTime    : 22/12/2011 22:22:35
    LastInputTime     : 22/12/2011 22:22:35
    LoginTime         : 22/12/2011 10:40:21
    IdleTime          : 10:38:06.4220944
    SessionId         : 33
    UserName          : admin
    

    【讨论】:

    • 我尝试执行该操作并收到以下错误。我也搜索了该链接,但没有有用的信息。使用“0”参数调用“打开”的异常:“RPC 服务器不可用”在 D:\My_Scripts\Mstsc-monitor.ps1:4 char:13 + $server.Open
    • 您是否将 替换为您的服务器的主机名?
    • 我在您的服务器名称中使用了 IP 地址。
    • 检查您是否可以在端口 445 上远程登录您的服务器。Telnet &lt;serverip&gt; 445
    • 感谢您的提示。那个港口被关闭了。我用另一台打开了该端口的机器验证了它。它工作正常
    【解决方案3】:

    如果您可以与服务器本身建立 RPC 连接,您可以使用QWinsta.exe 查看谁在登录 TS,并使用RWinsta.exe 远程关闭连接 (see Managing Terminal Services Sessions Remotely)

    【讨论】:

      【解决方案4】:

      我每 15 分钟运行一次此功能,它依赖于模块 PSTerminalServices。基本上它的作用是,它会提取最后一次有人 RDP 进入,然后将其存储在 XML 中,如果存在则覆盖旧值,如果当前没有人登录,则返回 XML 中的最新值。

      Function Get-LastLogonTime
      {
      <#
      
      .SYNOPSIS
      
      Get-LastLogonTime returns the last date that someone logged on to a computer.
      
      .DESCRIPTION
      
      Get-LastLogonTime returns the last date that someone logged to a computer.
      If admin rights are missing on the server it will return False.
      
      .EXAMPLE
      
      Get-LastLogonTime "nameofcomputer"
      
      .NOTES
      
      gets last access time from the user folder
      
      .LINK
      
      http://winfred.com
      #>
      Param(
      [Parameter(Position=0, Mandatory=$true)]$ComputerName
      )
          $StoredRDPSessions = Import-Clixml "RDPSessions.xml"
      
          $myobj = "" | select ComputerName, LastAccessedDate, UserName
          $myobj.ComputerName = $ComputerName
          $LastConnectedUser = Get-TSSession -ComputerName $ComputerName | where `
          {
              ($_.WindowStationName -ne "Services") -and `
              ($_.State -ne "Listening") -and `
              ($_.WindowStationName -ne "Console")
          } | sort-object -property LastAccessTime -Descending
          if($LastConnectedUser -is [array])
          {
              $myobj.LastAccessedDate = $LastConnectedUser[0].ConnectTime
              $myobj.UserName = $LastConnectedUser[0].UserName
          }elseif($LastConnectedUser){
              $myobj.LastAccessedDate = $LastConnectedUser.ConnectTime
              $myobj.UserName = $LastConnectedUser.UserName
          }else{
              $myobj.LastAccessedDate = $Null
              $myobj.UserName = "Unknown"
          }
          if(($myobj.LastAccessedDate) -and ($myobj.UserName))
          {
              $StoredRDPSession = $StoredRDPSessions | where {$_.ComputerName -eq $ComputerName}
              if($StoredRDPSession)
              {
                  if($myobj.LastAccessedDate -gt $StoredRDPSession.LastAccessedDate)
                  {
                      write-verbose "Newer LastAccessedDate, updating XML"
                      $StoredRDPSession.LastAccessedDate = $myobj.LastAccessedDate
                      $StoredRDPSession.UserName = $myobj.UserName
                      $StoredRDPSessions | Export-Clixml "RDPSessions.xml"
                  }
              }else{
                  write-verbose "No Entry found Adding to XML"
                  $NewStoredRDPSessions = @()
                  $StoredRDPSessions | % {$NewStoredRDPSessions += $_}
                  $NewStoredRDPSessions += $myobj
                  $NewStoredRDPSessions | Export-Clixml "RDPSessions.xml"
              }
          }
      
          if((!($myobj.LastAccessedDate)) -and $StoredRDPSessions)
          {
              write-verbose "no current session, pulling from stored XML"
              $StoredRDPSession = $StoredRDPSessions | where {$_.ComputerName -eq $ComputerName}
              if($StoredRDPSession)
              {
                  $myobj.LastAccessedDate = $StoredRDPSession.LastAccessedDate
                  $myobj.UserName = $StoredRDPSession.UserName
              }else{
                  write-verbose "Sadness, nothing stored in XML either."
              }
          }
          write-verbose "Get-LastLogonTime $ComputerName - $($myobj.LastAccessedDate) - $($myobj.UserName)"
          Return $myobj
      }
      

      【讨论】: