我需要从键盘鼠标最后一次激活时获得时间 - 但是在远程计算机上。 - 它需要适用于任何用户,即使他们通过远程桌面连接。
我已经能够在C#控制台应用程序和PowerShell脚本中通过P /调用来自User32.dll的GetLastInputInfo
在本地计算机(甚至是RDP会话)上获取此信息
然而,通过远程PowerShell(或通过后台服务)提供相同的代码会给我错误的信息(它基本上只是给我机器的正常运行时间,好像没有处理任何输入事件)。
如何从远程计算机获取上次键盘/鼠标活动的正确时间? (即,从远程PowerShell上下文或Windows服务上下文中运行的代码)。
也许有一些设置我可以更改为后台进程访问当前登录的用户会话? - 或者我可以更改注册表设置? - 或许有一种方法可以枚举活动会话并将会话对象传递给某种GetLastInputInfoEx
函数或其他东西? - 我怎样才能继续前进?
我当前的PowerShell脚本看起来像这样(我使用的C#版本也应该很明显):
$signature = @'
[DllImport("User32.dll")]
private static extern bool GetLastInputInfo(ref LastInputInfo plii);
public struct LastInputInfo
{
public uint Size;
public uint Time;
}
public static TimeSpan? GetIdleTime()
{
LastInputInfo lastInput = new LastInputInfo();
lastInput.Size = (uint)Marshal.SizeOf(lastInput);
uint envTicks = (uint)Environment.TickCount;
if (GetLastInputInfo(ref lastInput))
{
double ms = envTicks - lastInput.Time;
if (ms >= 0)
{
return TimeSpan.FromMilliseconds(ms);
}
}
return null;
}
'@
$type = Add-Type -Name "User32Utils" -Namespace "InteropHelpers" -MemberDefinition $signature -PassThru
return [InteropHelpers.User32Utils]::GetIdleTime();
答案 0 :(得分:1)
感谢comment above Scott Chamberlain,我能够找到使用Cassia的解决方案(我通过他们的NuGet Package消费)。
免责声明:请注意,这仅适用于RDP会话。 (当我测试Cassia时,它无法返回非RDP会话的IdleTime
或LastInputTime
数据.YMMV,但它适用于我,因为我编写代码来监视VM只能通过RDP访问。
此外,虽然不是绝对必要,但我选择通过编写一个快速的PowerShell Cmdlet来展示Cassia提供的数据(它的Class Library
名为" CassiaCmdlet.dll& #34;其中包含一个单词):
using System;
using System.Management.Automation;
using Cassia;
namespace CassiaCmdlet
{
[Cmdlet("Get", "TsSession")]
public class GetTsSession : Cmdlet
{
[Parameter(Position = 0)]
[Alias("ServerName", "MachineName", "Name")]
public string ComputerName { get; set; }
/// <summary>
/// Processes the record.
/// </summary>
protected override void ProcessRecord()
{
using (var server = GetServer())
{
server.Open();
foreach (var session in server.GetSessions())
{
WriteObject(session);
}
server.Close();
}
}
private ITerminalServer GetServer()
{
var mgr = new TerminalServicesManager();
if (string.IsNullOrWhiteSpace(ComputerName))
{
// Local Machine
return mgr.GetLocalServer();
}
else
{
// Remote Machine
return mgr.GetRemoteServer(ComputerName);
}
}
}
}
然后从PowerShell:
[Fubar]: PS C:\Scripts\Cmdlets> Import-Module .\CassiaCmdlet.dll
[Fubar]: PS C:\Scripts\Cmdlets> Get-TsSession
<... snip ...>
ClientDisplay : Cassia.Impl.ClientDisplay
ClientBuildNumber : 0
Server : Cassia.Impl.TerminalServer
ClientIPAddress :
WindowStationName :
DomainName : Fubar
UserAccount : Fubar\Spock
ClientName :
ConnectionState : Disconnected
ConnectTime : 5/15/2017 11:03:07 PM
CurrentTime : 5/15/2017 11:25:51 PM
DisconnectTime : 5/15/2017 11:04:56 PM
LastInputTime : 5/15/2017 11:04:56 PM
LoginTime : 5/15/2017 10:44:34 PM
IdleTime : 00:20:54.7733923
SessionId : 2
UserName : Spock
<... snip ...>
值得注意的是,对于远程 PowerShell系统,会话对象中的日期为本地时间。因此,您可能希望在使用它们之前将它们转换为通用时间。
另外值得注意的是,已连接的会话将有WindowStationName
类似&#34; RDP *&#34;,但同一会话一旦断开连接,将具有空名称(它仍然具有{{1虽然!)。
使用它的一个简单示例如下:
LastInputTime
这过滤了&#34; RDP *&#34;或&#34;&#34 ;;理想情况下,您只需过滤掉PowerShell会话。 (我认为默认名称为&#34; Console&#34;,但是如果您从C#连接,则可以将其命名为任何名称,因此我保持代码简单。)