К сожалению, на самом деле нет никаких чистых способов сделать это, по крайней мере, я не смог бы найти, если только вы не захотите использовать что-то вроде query user
с PsExec
для удаленного выполнения этого на каждом ПК в качестве подпрограммы. обработать, а затем проанализировать результаты. Даже тогда, когда вы не получите прямого ответа о заблокированном состоянии, вам придется перейти в режим ожидания, так как Статус показывает, что один из пользователей активен, когда никто не использует компьютер.
Тогда существует проблема с несколькими пользователями, которые вошли в систему на компьютере, используя функциональность Switch User в Windows 7 или выше. В моей среде ПК может иметь 3 или 4 фоновых пользователя и одного пользователя консоли. В некоторых случаях ПК используются пользователями RDP. И оказывается, что есть особый случай, когда вы подключаетесь к компьютеру, а затем входите в консоль или делаете обратное, поскольку LogonSession LogonType в этих случаях не обновляется. К сожалению, также возможно поймать пользователя, только входящего в компьютер, и в этом случае моя функция неправильно скажет, что компьютер не используется.
На моем компьютере и в сети эта функция запускается примерно за 0,2 секунды, если компьютер включен. На некоторых ПК это может занять гораздо больше времени (до 20 секунд), поскольку на ПК загружается поставщик perfmon. Если компьютер выключен, время ожидания достаточно велико, и если это возможно, я бы рекомендовал сначала выполнить проверку пинга.
В основном функция использует WMI для получения информации LogonSession и Interactive Desktops, а Process
для получения процессов LogonUI и проводника. Поскольку LogonSession возвращает старые сеансы, которые вышли из системы, и сеансы для программ администратора UAC и других (Windows 10) фоновых процессов (DWM / UMFD), мы учитываем только те сеансы LogonSession, которые имеют процесс explorer.exe
(рабочий стол).
Затем объединяет информацию в разные случаи:
Если число процессов LogonUI больше или равно количеству интерактивных рабочих столов, ПК либо вышел из системы, либо заблокирован. Если на ПК есть LogonSessions (с проводником), он блокируется, иначе он выходит из системы.
Если число процессов LogonUI меньше количества интерактивных рабочих столов, значит, ПК используется.
Вот код:
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;
}
}