1

Тема: JScript: Вывод списка пользователей на каждом контроллере домена...

... с указанием даты последнего входа пользователя в домен.

Поскольку пользователь мог ни разу не входить в домен, дата входа в зависимости от версии Windows Server (2000, 2003) может быть как 0, так и null (<Not Set>). Если дата входа равна 0, то она выводится как "1 января 1601 г. 0:00:00". Если она равна null, то выдается сообщение "Значение lastLogon для текущего пользователя отсутствует".

Скрипт может (и должен) использоваться для отслеживания неактивных пользователей.

Оговорка - делать на основе этого скрипта автоматическое удаление неактивных пользователей нужно осторожно, так как в неактивных могут присутствовать пользователи, созданные системой автоматически для своих нужд. Удалять их не рекомендуется. В теме http://forum.script-coding.com/viewtopic.php?id=859 были попытки найти способ отличить системных пользователей от "ручных", но универсальный способ пока не найден.

За помощь в тестировании скрипта и высказанные замечания спасибо alexii.

var WSH = new ActiveXObject ('WScript.Shell');

// Если скрипт запущен через WScript, ругаемся и выходим
if (WScript.FullName.toLowerCase() == (WScript.Path+'\\wscript.exe').toLowerCase()) {
      WSH.Popup('Запуск сценария производится только через '+WScript.Path+'\\cscript.exe.\n\nВыходим...', 0, 'Ошибка', 16);
      WScript.Quit();
}

var Stdout = WScript.Stdout;
var Stdin  = WScript.Stdin;
var objDict = new ActiveXObject("Scripting.Dictionary");
var objConnection = new ActiveXObject("ADODB.Connection");
var objCommand = new ActiveXObject("ADODB.Command");
var oRoot = GetObject("LDAP://rootDSE");
var sDomain = oRoot.Get("defaultNamingContext");

var strLDAP  = "LDAP://OU=Domain Controllers," + sDomain;
var ADS_SCOPE_SUBTREE = 2;
var space = '                                                                                                                                       ';
var date1601 = Math.abs((new Date(1601,0,1)).getTime())
var strDC, temp, arr

// Формируем запрос на поиск всех серверов домена ========================
objConnection.Provider = "ADsDSOObject";
objConnection.Open("Active Directory Provider");

objCommand.ActiveConnection = objConnection;
objCommand.Properties("Page Size") = 500;
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE;
objCommand.Properties("Sort On") = "sAMAccountName";
objCommand.CommandText = "SELECT sAMAccountName,adsPath FROM '" + strLDAP + "' WHERE objectCategory='computer'";
// =======================================================================

// Выполняем запрос
var objRSServers = objCommand.Execute;

// Перебираем все найденные серверы и добавляем юзеров в глобальный
// для сценария словарь objDict (в функции GetUsers)
while ( !objRSServers.EOF ) {
   strDC = objRSServers.Fields("sAMAccountName").Value;
   GetUsers(strDC.substr(0, strDC.length-1 ));
   objRSServers.moveNext()
}

// сортируем логины по алфавиту
arr = (new VBArray(objDict.Keys())).toArray();
for (var i = arr.length - 1; i>=0; i--) {
   for (var j= 0; j<i; j++) {
      if ( arr[j]>arr[j+1] ) {
         temp=arr[j+1];
         arr[j+1]=arr[j];
         arr[j]=temp;
      }
   }
}

// Перебираем всех найденных юзверей
var name, lastLogon, age, Item
var comment = '   <Значение lastLogon для текущего пользователя отсутствует>';
for (var usr in arr)
{
   name = arr[usr];

   Stdout.Write( (name+space).substr(0,30) );

   lastLogon = objDict(name);
   if(lastLogon instanceof Date) {
      age = (new Date() - lastLogon)/(86400*1000);
      Stdout.WriteLine( ("Дата последнего входа: " +(lastLogon).toLocaleString()+space).substr(0,53)+
                        "("+(space+age.toFixed(0)).slice(-7)+" дней назад)" );
   } else {
      Stdout.WriteLine( comment );
   }

}

Stdout.WriteLine ("\nНажмите Enter");
Stdin.ReadLine ();


//
// FUNCTIONS
//


// Выбирает всех пользователей на заданном сервере домена в ассоциативный массив
function GetUsers( strDC ) {
var dLastLogin;
var Conn = new ActiveXObject("ADODB.Connection");
var RSUsers = new ActiveXObject ("ADODB.Recordset");
var query = "SELECT sAMAccountName, lastLogon FROM 'LDAP://" + strDC + "' WHERE objectCategory='user'"

   Stdout.WriteLine("Список пользователей на: " + strDC);

   Conn.Provider = "ADsDSOObject";
   Conn.Open("Active Directory Provider");
   RSUsers.ActiveConnection = Conn;

   for ( RSUsers.Open (query); !RSUsers.EOF; RSUsers.moveNext() ) {

      // Для уникальности имени добавляем к нему имя DC
      sAMAccountName = strDC+": "+RSUsers.Fields("sAMAccountName").Value;

      if ( dLastLogin = RSUsers.Fields("lastLogon").Value ) {
         // сюда попадаем, когда у атрибута есть значение (любое)
         dLastLogin     = getLast(dLastLogin);
      } else {
         // сюда попадаем, когда атрибута нет значения (<Not Set>)
      }

      AddToDict(sAMAccountName, dLastLogin)
   }
}


// добавляет в ассоциативный массив значение с примечанием
function AddToDict(name, value) {
   if (!objDict.Exists (name) ) {
      objDict.Add ( name, value );
   } else {
      objDict(name) = value;
   }
}

// конвертирует lastLogon, возвращенный запросом к LDAP, в удобоваримую дату
function getLast( last ) {
var res,
    intLastLogonTime = last.HighPart* (4294967296) + last.LowPart;

   res = intLastLogonTime / 10000;
   res = res - date1601;

   return (new Date(res));
}

2

Re: JScript: Вывод списка пользователей на каждом контроллере домена...

Если стоит задача блокировки учетных записей, неактивных более определённого количества дней, эту задачу можно в некоторых случаях решить и без скриптов, интерактивно:
1. Установить "Windows Server 2003 Service Pack 2 Administration Tools Pack" (adminpak_sp2.msi), на WinXP SP2 ставится без проблем.
2. Запустить mmc.exe, подключить оснастку "Active Directory Users and Computers".
3. В ветви "Saved Queries" в контекстном меню - "New" - "Query".
4. В окне "New Query" кнопка "Define Query...", затем в окне поиска задать нужное значение в поле "Days since last logon".
5. В правой панели оснастки выделить всех найденных пользователей, в контекстном меню - "Disable Account".

Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.