首页 > 解决方案 > 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

}

标签: c#windows

解决方案


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

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

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

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

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

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

  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;
    }
}

推荐阅读