Windows-在运行测试之前检查计算机是否已锁定/注销

时间:2019-04-22 15:27:54

标签: c# windows

我有一套UI测试,可以根据情况在本地/远程运行。有时,只要有重要更新要应用,远程计算机就会自动重新启动。这会导致所有测试超时,因为运行它们的远程计算机被锁定,并且无法再访问GUI。

我想知道如何快速检查计算机是否被锁定,这样我可以快速通过测试并记录它们是否处于脱机状态。

我在网上找到了该解决方案,但它似乎更适合开发而不是测试。

https://bytes.com/topic/net/answers/770957-get-computer-state-locked-stand-c

真的只是想要一种干净的方法来检查当前计算机是否已使用C#库锁定,然后将其放入类似下面的方法中。

public bool IsWindowsLocked(){

     // Check if the current machine is in a locked state

}

1 个答案:

答案 0 :(得分:2)

不幸的是,实际上并没有任何干净的方法可以做到这一点,至少我找不到,除非您愿意将query userPsExec一起使用以在每台PC上远程执行它作为子过程,然后解析结果。即使这样,您也无法直接获得有关锁定状态的答案,您还必须等待空闲时间,因为当没有人使用计算机时,状态会显示其中一个用户为活动用户。

然后,存在使用Windows 7或更高版本中的“切换用户”功能在计算机上登录多个用户的问题。在我的环境中,一台PC可能有3或4个后台用户和一个控制台用户。在某些情况下,RDP用户使用PC。事实证明,当您将RDP连接到计算机,然后再登录到控制台或执行相反的操作时,是一种特殊情况,因为在这些情况下,LogonSession LogonType不会更新。不幸的是,也有可能抓住刚登录计算机的用户,在这种情况下,我的功能将错误地指出计算机未使用。

在我的PC和网络上,如果PC开启,则此功能大约需要运行0.2秒。在某些PC上,可能需要更长的时间(最多20秒),因为它会在PC上加载perfmon提供程序。如果PC关闭,则超时时间很长,如果有可能,我建议您先执行ping检查。

该函数基本上使用WMI来获取LogonSession和Interactive Desktops信息,并使用Process来获取LogonUI和资源管理器进程。由于LogonSession返回已注销的旧会话以及UAC Admin程序和其他(Windows 10)后台进程(DWM / UMFD)的会话,因此,我们仅计算具有explorer.exe进程(桌面)的LogonSessions。

然后将信息组合成不同的情况:

  1. 如果LogonUI进程数大于或等于交互式桌面数,则PC已注销或已锁定。如果PC上有任何LogonSession(带有资源管理器),它将被锁定,否则将被注销。

  2. 如果LogonUI进程的数量少于交互式桌面的数量,则说明PC正在使用。

代码如下:

enum PCUserStatuses {
    Locked, // all users are locked
    LoggedOff, // No users are logged in
    InUse, // A user is using this computer
    Unknown // unable to connect to computer / other error
}

PCUserStatuses GetPCUserStatus(string machineName) {
    try {
        var scope = GetManagementScope(machineName);
        scope.Connect();

        var explorerProcesses = Process.GetProcessesByName("explorer", machineName)
                                    .Select(p => p.Id.ToString())
                                    .ToHashSet();

        var REprocessid = new Regex(@"(?<=Handle="").*?(?="")", RegexOptions.Compiled);

        var numberOfLogonSessionsWithExplorer = new ManagementObjectSearcher(scope, new SelectQuery("SELECT * FROM Win32_SessionProcess")).Get()
                                                    .Cast<ManagementObject>()
                                                    .Where(mo => explorerProcesses.Contains(REprocessid.Match(mo["Dependent"].ToString()).Value))
                                                    .Select(mo => mo["Antecedent"].ToString())
                                                    .Distinct()
                                                    .Count();

        var numberOfUserDesktops = new ManagementObjectSearcher(scope, new SelectQuery("select * from win32_Perfrawdata_TermService_TerminalServicesSession")).Get().Count - 1; // don't count Service desktop
        var numberOflogonUIProcesses = Process.GetProcessesByName("LogonUI", machineName).Length;

        if (numberOflogonUIProcesses >= numberOfUserDesktops) {
            if (numberOfLogonSessionsWithExplorer > 0)
                return PCUserStatuses.Locked;
            else
                return PCUserStatuses.LoggedOff;
        }
        else
            return PCUserStatuses.InUse;
    }
    catch {
        return PCUserStatuses.Unknown;
    }
}