Как вычислить имя компьютера пользователя в Active Directory
Добрый день! Уважаемые читатели и гости одного из крупнейших IT блогов в России Pyatilistnik.org. В прошлый раз мы с вами производили поиск неактивных пользователей в домене. Сегодня мы сделаем еще одну полезную вещь для нашего AD, а именно научимся автоматически определять DNS-имя компьютера на котором локально залогинен пользователь и заносить эту информацию в атрибут Active Directory у пользовательской учетной записи.
Постановка задачи
В компаниях, где есть техническая поддержка пользователей, ее инженеры очень часто подключаются удаленно к компьютерам сотрудников для устранения всевозможных проблем. Чаще всего используются программы TeamViewer, встроенный помощник Windows или Dameware. Но для того, чтобы подключиться вам необходимо знать имя компьютера. Понятно, что можно каждый раз просить пользователя посмотреть его либо в окне системы или же на рабочем столе, если у вас выводится информация с помощью BGinfo. Но проще и правильнее всегда эту информацию иметь в базе Active Directory.
Поэтому мы сделаем так, что при локальном входе в компьютер, информация, о его DNS-имени будет автоматически записана в нужное нам поле. Это удобно и можно легко эту информацию выдергивать в любую программу, которая умеет работать с Active Directory, например SCCM.
Необходимо с помощью VBS скрипта записывать имя компьютера на котором пользователь произвел локальный вход, но игнорировать подключения к удаленному рабочему столу, например на терминальные сервера.
Реализация задачи
Делать мы все будет с помощью вот такого простенького скрипта.
Set objSysInfo = CreateObject("ADSystemInfo")
strUserDN = objSysInfo.UserName
Set objUser = GetObject("LDAP://" & strUserDN)
objUser.Put "Pager", WshNetwork.ComputerName
objUser.SetInfo
Давайте с вами пробежимся по каждой из строчек кода.
- Set WshNetwork = WScript.CreateObject("WScript.Network") - это объект VBSScript позволяет получать информацию по трем свойствам имя компьютера ComputerName, имя пользователя UserNam, имя домена UserDomain и методы MapNetworkDrive(), AddPrinterConnection(), SetDefaultPrinter(). Объект WScript.Network очень часто используется в WSH. У созданного объекта - всего три свойства и восемь методов, но они могут оказаться очень полезными. Свойства ComputerName, UserDomain и UserName возвращают, соответственно, имя компьютера, имя домена и имя текущего пользователя. Очень удобно:
- для протоколирования выполнения скрипта - записывается информация о том, на каком компьютере произошло то или иное событие;
- для выполнения каких-либо действий только на том компьютере или только с тем пользователем, который указан в нашем списке (при помощи утилит Resource Kit можно основываться и на членстве пользователей в группах).
- Кроме того, можно просто отображать полученную информацию - например, на Web-странице, которая используется в качестве обоев для пользователя.
- Set objSysInfo = CreateObject("ADSystemInfo") - создание экземпляра объекта ADSystemInfo. Это невероятно полезный объект, который может возвращать всевозможную информацию о вошедшем в систему пользователе и локальном компьютере. Единственным недостатком этого объекта является тот факт, что он может быть создан только локально: вы не можете создать экземпляр ADSystemInfo на удаленном компьютере, а затем получить информацию о пользователе, вошедшем в систему на этом компьютере.
- strUserDN = objSysInfo.UserName - получаем значение свойства strUserDN и сохраняем его в переменной с именем strUser
- Set objUser = GetObject("LDAP://" & strUserDN) - используем эту переменную как часть вызова GetObject, который связывает нас с учетной записью пользователя.
- objUser.Put "Pager", WshNetwork.ComputerName - изменение атрибута с помощью метода Put. В моем случае, это атрибут пейджер
- objUser.SetInfo - подтверждаем изменения в каталоге методом SetInfo
Вы вместо атрибута "Pager" можете подставлять любой, посмотреть атрибуты можно через редактор в Active Directory. Далее создаете текстовый документ и сохраняете его с расширением vbs.
Создание политики во время входа в систему
Файл со скриптом у меня готов. Открываем оснастку "Управление групповой политикой". Выбираем нужное организационное подразделение к которому мы будем применять политику, в моем случае, это контейнер "Users", поэтому политику я буду применять на самый корень домена root.pyatilistnik.org. Кликаем по нему правым кликом и из контекстного меню выбираем пункт "Создать объект групповой политики в этом домене и связать его".
Задаем имя для нашей политики.
Далее нам необходимо изменить и настроить нашу политику. Для этого щелкаем по ней правым кликом и выбираем "Изменить".
Переходим по пути:
У вас откроется окно с вкладкой "Сценарии" и "Сценарии PowerShell". Нас будет интересовать первая вкладка, нажимаем кнопку "Добавить".
Через кнопку "Обзор" вам нужно будет выбрать ваш файл vbs. Я вам советую его скопировать в сетевую папку с политикой, либо в сетевую шару, где файл будет доступен для всех.
В итоге у вас должно появиться вот так, если скриптов более одного, то можно выставлять их позиции при применении. Начинаем тестирование. У меня есть тестовая учетная запись Барбоскина Геннадия, в оснастке ADUC она у меня лежит в контейнере "Users". Поле пейджер пустое.
Пробуем залогиниться Геннадием на рабочей станции с Windows 10 с именем W10-CL01. После входа на компьютер, проверяем свойство "Пейджер" у данного пользователя. Как видим, все прописалось.
Пробуем подключиться к еще одному компьютеру с Windows 10 под именем W10-CL02. Видим, что атрибут в AD изменил свое значение на имя второго компьютера.
Скрипт PowerShell для записи имени системы куда был последний вход
Все то же самое можно сделать и на PowerShell, и как показала практика данный скрипт работает на более современных версиях Windows 10 и Windows 11 без проблем, да и вообще он более современный, его так же можно применять в автозагрузке с помощью групповой политики.
function Date {Get-Date -Format "yyyy.MM.dd HH:mm:ss"}
$log = "$($env:ProgramData)\Update_Pager_attribute.log"
$computername = "$((Get-WmiObject Win32_ComputerSystem).Name).$((Get-WmiObject Win32_ComputerSystem).Domain)"
$username = "$($env:USERDOMAIN)\$($env:USERNAME)"
"$(Date) Trying to set user $username Pager attribute value to $computername" | Tee-Object $log -Append
$current_user = [adsisearcher]"(&(samaccountname=$($env:USERNAME)))"
try {
$ad_user = $current_user.FindOne().GetDirectoryEntry()
$ad_user.Put("Pager",$computername)
$ad_user.SetInfo()
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
}
еще вариант скрипта:
function Date {Get-Date -Format "yyyy.MM.dd HH:mm:ss"}
$log = "$($env:ProgramData)\Update_attributes.log"
$computername = "$((Get-WmiObject Win32_ComputerSystem).Name).$((Get-WmiObject Win32_ComputerSystem).Domain)"
$username = "$($env:USERDOMAIN)\$($env:USERNAME)"
"$(Date) Trying to set user $username Pager attribute value to $computername" | Tee-Object $log -Append
$current_user = [adsisearcher]"(&(samaccountname=$($env:USERNAME)))"
try {
$ad_user = $current_user.FindOne().GetDirectoryEntry()
$ad_user.Put("Pager",$computername)
$ad_user.SetInfo()
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
}
###
if ($((Get-WmiObject Win32_ComputerSystem).Domain) -eq "root.pyatilistnik.org")
{
$value_to_add = "$(Date) - $($env:USERNAME)"
"$(Date) Trying to add `"$value_to_add`" string to Info attribute value for $computername" | Tee-Object $log -Append
$comp_name = "$((Get-WmiObject Win32_ComputerSystem).Name)$"
$comp_object = [adsisearcher]"(&(samaccountname=$comp_name))"
$comp = $comp_object.FindOne().GetDirectoryEntry()
# $values_current = @()
# $values_current = $comp.Properties["Info"].Value -split ";"
# $comp.Properties["Info"].Value
$value_new = $null
$value_new = "$($comp.Properties["Info"].Value);$value_to_add"
$values_new = $value_new -split ";"
if ($values_new.Length -gt 3)
{
$value_new = ($values_new | select -Last 3) -join ";"
}
# $value_new
###
try {
$comp.Put("Info", $value_new)
$comp.SetInfo()
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
}
}
Напоминаю, что записываться будут только локальные входы. Сама реализация до безобразия проста, но надежна. Надеюсь, что кому-то данная заметка оказалась полезной, а с вами был Иван Семин, автор и создатель IT блога Pyatilistnik.org.
Может лучше IP-адрес запилить?!
Задачи у всех разные, у заказчика была такая хотелка
Как все оказывается просто. Очень полезный скриптик, для не замороченны.Спасибо большое!
Да скрипты, это сила
А что значит «только локальные входы»?
У нас в некоторых пользователях есть по два компьютера. Они заходят на эти компьютеры со одной учётной записью. Можно сделать так, чтобы оба имя компьютера отображалось в пейджере.
Можно, взяв второе поле, например номер комнаты или создать свое в схеме AD, у меня возможно было, что-то подобное на PowerShell
те которые совершены интеративно, без РДП, так сказать консольно
Если у пользователя два компьютера, и на оба компьютера заходят с одной учетной записью, то тогда как можно сделать так чтобы в пейджерах отображались оба имя компьютера
To Галым, примерно так:
Set WshNetwork = WScript.CreateObject(«WScript.Network»)
Set objSysInfo = CreateObject(«ADSystemInfo»)
strUserDN = objSysInfo.UserName
Set objUser = GetObject(«LDAP://» & strUserDN)
On Error Resume Next
Err.Clear
Pager = objUser.Get(«Pager»)
If Err.Number 0 Then
Pager = «»
Err.Clear
End If
On Error Goto 0
CurrentComputer = WshNetwork.ComputerName
If InStr(1, «;» & Pager & «;», «; & CurrentComputer & «;», vbTextCompare) = 0 Then
objUser.Put «Pager», Pager & CurrentComputer & «;»
objUser.SetInfo
End If
Добрый день! А если у меня не отрабатывает скрипт, я проделал все описанное выше.
Нужно посмотреть в логах
Добрый человек, подскажи как такое сделать через PowerShell и чтобы имя пользователя подставлялось в описание
КАК игнорировать к удаленному рабочему столу, например на терминальные сервера?
Подскажите пожалуста.
У меня добавляєт терминальние сервера, как их игнорировать?
Не совсем понимаю, что значит игнорировать?
когда пользователь откривает remoteapp то имя сервера remoteapp также записивает.
как исправить ето?
Куда записывает-то?
Объясню подробно.
То есть, сначала при локальном входе пользователя записываеться его имя пк как положено. Все работает. Например «PC-04»
Однако как только этот пользователь входит на терминальный сервер «server-22», или открывает remoteapp — строка «пейджер» перезаписываться на имя сервера терминалов, и в строке «пейджер» теперь вместо «PC-04» записано «server-22»
В политике примените WMI фильтр (распространите только операционные системы, кроме серверных)
А это решение, спасибо за подсказку.
при запуске сценария PS ошибку выдает- Исключение при вызове «SetInfo» с «0» аргументами: «Отказано в доступе.
если запускать под другим пользователем с правами админа домена то лог работает,
подскажите в чем собственно проблема ?
при запуске vbs скрипта ошибка
Отказано в доступе
код 80070005