Время последнего входа в систему

в 22:16, , рубрики: Песочница, метки: ,

В составе SysInternals Suite помимо прочего есть такая утилита, как PsLoggedOn, отображающая, как несложно догадаться из названия, время входя в систему пользователя, — весьма полезная информация для системного администратора. Но суть скорее здесь в том, как вышеобозначенная утилита получает эти сведения, а способов между тем довольно много: от считывания времени модификации ключа реестра HKEY_CURRENT_USERVolatile Environment до задействования таких API-функций как LsaEnumerateLogonSessions, LsaFreeReturnBuffer, LsaGetLogonSessionData, — но то все про различные языки программирования. Как на счет штатных средств, но без WMI?

Остановил свой выбор я на VBScript, и если кто-то поморщит нос при упомянании последнего, дескать, это что-то из рода некрофилии, позвольте напомнить, что еще довольно много пользователей Windows использующих ХР, причем далеко не у всех них установлен PowerShell. В виду чего выбор считаю оправданным.
Одним из условий, которое было поставлено — не использовать WMI. Несложно догадаться, что в таком случае будем ковырять реестр. Не то, чтобы в забой по стахановски, нужны будут лишь такие ветви реестра, как HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTimeZoneInformation и HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionProfileList. В первой нас интересует параметр ActiveTimeBias (смещение относительно часового пояса), во втором — ProfileLoadTimeLow и ProfileLoadTimeHigh текущего пользователя, представляющих собой поля структуры FILETIME. Все просто. Единственное, что может вызвать затруднение — как найти текущего пользователя, если WSH предоставляет доволько скудные возможности по работе с реестром? Будем использовать утилиту reg.exe из стандартной поставки Windows.

Dim objBias, strType, objExec, objData, objRexp, strUser
Dim tz, i, lowPart, highPart

With CreateObject("WScript.Shell")
  objBias = .RegRead("HKLMSYSTEMCurrentControlSetControlTimeZoneInformationActiveTimeBias")
  strType = UCase(TypeName(objBias))
  
  If strType = "LONG" Then
    tz = objBias
  ElseIf strType = "VARIANT()" Then
    tz = 0
    For i = 0 To UBound(objBias)
      tz = tz + (objBias(i) * 256 ^ i)
    Next
  End If
  
  'ищем пользователя по имени
  Set objExec = .Exec("cmd /q /k echo off")
  objExec.StdIn.WriteLine _
    "reg query ""HKLMSOFTWAREMicrosoftWindows NTCurrentVersionProfileList"" /s & exit"
  objData = Split(objExec.StdOut.ReadAll, vbCrLf)
  
  Set objRexp = New RegExp
  objRexp.Pattern = CreateObject("WScript.Network").UserName
  objRexp.IgnoreCase = True
  objRexp.Global = True
  
  For i = 0 To UBound(objData)
    If objRexp.Test(objData(i)) Then
      strUser = objData(i - 1)
      Exit For
    End If
  Next
  
  'strUser = HKLMSOFTWAREMicrosoftWindows NTCurrentVersionProfileListSID
  lowPart  = .RegRead(strUser & "ProfileLoadTimeLow")
  highPart = .RegRead(strUser & "ProfileLoadTimeHigh")
  
  'конвертируем поля FILETIME в дату
  WScript.Echo ((highPart * (2 ^ 32) + lowPart) / (60 * 10000000) - tz) / 1440 + #1/1/1601#
End With

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js