ShS's Blog

Just another sysadmin's weblog

Скрипт для записи в атрибут Description объекта-компьютера в AD имени текущего «залогоненного» пользователя

Posted by shs на 2010/01/21

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

  1. подойти к пользователю и посмотреть в свойствах «Моего компьютера» имя этого компьютера ;)
  2. узнать имя компьютера у пользователя
  3. выполнить опрос всех компьютеров в организации на предмет имени текущего пользователя и найти среди этих имен нужного нам пользователя, а, значит, и проблемный компьютер.
  4. заглянуть в некую БД, в которой хранится информация о том, какой компьютер был установлен на рабочем месте данного пользователя.

 Понятно, что первый вариант мы не рассматриваем, как ущербный. Второй вариант вполне удобоварим, если мы сможем упростить задачу поиска имени компьютера для конечного пользователя. Это реализуемо, но мы не будем сейчас останавливаться на этом вопросе. К тому же в идеальном случае нам бы хотелось, зная только имя пользователя и не задавая ему лишних вопросов, иметь возможность узнать имя компьютера, за которым он работает. Третий вариант всем хорош, за исключением того, что задача опроса всех компьютеров в организации занимает недопустимо много времени. Четвертый вариант успешно решает поставленную задачу, но порождает другую – кто (и каким образом) будет создавать и обновлять эту базу данных? Можно, конечно, вручную поддерживать в актуальном состоянии табличку в Excel, но «это же не наши методы» ;), хочется автоматизации. Если в вашей организации уже используется AD, то задача уже частично решена: у нас есть база данных, содержащая имена пользователей и компьютеров. Наша задача сводится к созданию связей компьютер-пользователь. Для этого можно, например, в один из атрибутов объекта компьютер записывать имя «залогоненого» на этом компьютере пользователя. В качестве такового атрибута я решил использовать атрибут Description (Описание). Этот атрибут пуст от рождения, может содержать произвольный тексты и по дефолту отображается в оснастке AD&С (dsa.msc), что позволит нам легко находить нужный нам компьютер по имени пользователя.

 Записывать имя пользователя в атрибут AD можно, как при помощи логон скрипта, так и при помощи скрипта, выполняющего опрос доступных компьютеров единовременно. У каждого из этих методов имеются свои плюсы и минусы. Меня вполне устроил второй вариант (т.к. в моем случае пользователи крайне редко меняют рабочий компьютер, а, значит, для отслеживания изменения в связке «компьютер-пользователь» скрипт опроса можно будет запускать также не часто. Кроме того, второй вариант позволяет одним разом прописать в AD информации по всем доступным рабочим станциям.)

 И так, вот, собственно сам скрипт:

Option Explicit 
Dim rootDSE,strDomainDN,objConnection 
Dim strSubContainer,objCommand,objRecordSet
Dim strMsg, arrDescription, strAccountProp, objComputer, strLoggedOnUser
'определяем константы
'символ-разделитель, используемый для формирования строки отчета
Const SPLITER = ","
'констатны, определяющие глубину поиска
Const ADS_SCOPE_SUBTREE = 2 
Const ADS_SCOPE_ONELEVEL = 1
'константа, выделяющая бит Enable|Disable из мультибитового атрибута userAccountControl
Const ADS_UF_ACCOUNTDISABLE = 2
'зададим контейнер AD, начиная с которого будем осуществлять поиск
strSubContainer="OU=WorkStations,OU=ORG," 
'получим DN домена
Set rootDSE = GetObject("LDAP://rootDSE") 
strDomainDN = rootDSE.Get("defaultNamingContext") 
'Выполняем подготовку обращения к AD при помощи ADODB
Set objConnection = CreateObject("ADODB.Connection") 
Set objCommand =   CreateObject("ADODB.Command") 
objConnection.Provider = "ADsDSOObject" 
objConnection.Open "Active Directory Provider" 
Set objCommand.ActiveConnection = objConnection 
'формируем SELECT-запрос к AD
objCommand.CommandText = "Select Name, " &_ 
        "operatingSystem, operatingSystemServicePack, Description, userAccountControl, distinguishedName " &_ 
        "from 'LDAP://"&strSubContainer&strDomainDN&"' " &_ 
        "Where objectClass='computer'" 
'определим максимальное количество объектов, возвращаемых в результирующем наборе записей
objCommand.Properties("Page Size") = 1000
'будем производить поиск по всему поддереву, начиная с заданного каталога 
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 'ADS_SCOPE_ONELEVEL 'ADS_SCOPE_SUBTREE 
'выполняем сформированный запрос, результатом которого является набор записей objRecordSet
Set objRecordSet = objCommand.Execute 
If objRecordSet.RecordCount<1 Then 
    WScript.Echo "No computer accounts found in "&strContainer&strDomainDN 
    WScript.Quit 
End If 
objRecordSet.MoveFirst 
Do Until objRecordSet.EOF
	''Выбираем только компьютеры, у которых Account установлен в Enabled
	''If ((InStr(objRecordSet.Fields("operatingSystem"),"XP")>0) And (InStr(objRecordSet.Fields("operatingSystemServicePack"),"2")>0)) Then
	If (objRecordSet.Fields("userAccountControl").Value And ADS_UF_ACCOUNTDISABLE)=0 Then
		'формируем строку отчета
    	strMsg = objRecordSet.Fields("Name").Value & _ 
    	SPLITER & objRecordSet.Fields("operatingSystem").Value & _
    	SPLITER & strAccountProp
    	arrDescription = objRecordSet.Fields("Description").Value
    	If Not IsNull (arrDescription) Then
    		strMsg = strMsg & SPLITER & arrDescription(0)
    	End If
    	WScript.Echo strMsg
    	'Вызываем функцию, возвращающую имя залогоненного пользователя на компьютере,
    	'имя компьютера передается в функцию в качестве параметра
    	strLoggedOnUser = fnGetUserName (objRecordSet.Fields("Name").Value)
    	WScript.Echo "LoggedonUser :" & strLoggedOnUser
    	'если имя залогонненого пользователя не пусто...
    	If (Not IsEmpty(strLoggedOnUser)) And (Not IsNull (strLoggedOnUser)) Then
    		'...записываем его в атрибут Description
			Set objComputer = GetObject("LDAP://"&objRecordSet.Fields("distinguishedName").Value)
    		objComputer.Put "Description" , strLoggedOnUser
			objComputer.SetInfo
    	End If
    End If
    objRecordSet.MoveNext 
Loop
'
'Эта функция опрашивает компьютер, чье имя передано ей в качестве параметра и
'возвращает имя залогоненного на опрашиваемом компьютере пользователя
Function fnGetUserName (strComputer)
On Error Resume Next
Dim objWMIService, colItems, objItem
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20

   Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
   Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem", "WQL", _
                                          wbemFlagReturnImmediately + wbemFlagForwardOnly)

   For Each objItem In colItems
      fnGetUserName = objItem.UserName
   Next
On Error GoTo 0
End Function

Пояснения к скрипту:

Для поиска информации в AD используем ADODB (см. Searching with ActiveX Data Objects (ADO)), что позволяет обращаться к AD, при помощи SQL-подобных запросов.

objCommand.CommandText = "Select Name, " &_ 
        "operatingSystem, operatingSystemServicePack, Description, userAccountControl, distinguishedName " &_ 
        "from 'LDAP://"&strSubContainer&strDomainDN&"' " &_ 
        "Where objectClass='computer'" 

Скрипт обрабатывает все компьютеры, найденные в поддереве, корнем которого является узел, заданный в переменной strSubContainer. Обратите внимание, что эта переменная должна содержать либо пустую строку (тогда будут обработаны все объекты-компьютеры в домене), либо часть DN узла (без имени домена), заканчивающуюся запятой. Так, например, если мы хотим выполнить поиск компьютеров в поддереве, корнем которого является OU “OU=Sys,DC=domain,DC=local”, то переменной strSubContainer нужно присвоить значение strSubContainer “OU=Sys, ” (не забудьте про последний символ — запятую)

 Запускать скрипт лучше с правами доменного администратора, т.к. эта группа безопасности обладает достаточными правами, как для работы функции fnGetUserName (для успешного функционирования которой требуются права лок.админа на целевом компьютере), так и для изменения атрибута Description объекта-компьютер в AD.

Реклама

комментариев 13 to “Скрипт для записи в атрибут Description объекта-компьютера в AD имени текущего «залогоненного» пользователя”

  1. […] shs на 2010/02/07 В предыдущих постах я разместил скрипты на VBScript и на PowerShell, которые записывают в атрибут Description […]

  2. […] […]

  3. gavrosh said

    а первый вариант(логон скрипт) написанный не имеется?

  4. gavrosh said

    спасибо, но к сожалению это работает только от админа( не подскажите как дать разрешение пользователю писать в АД свойство «описание»?

  5. gavrosh said

    прошу прощения за невнимательность, про делегировании я прочитал. у меня просто компы по разным оу раскиданы, от этого другой скрипт пляшет( всему домену что ли делегировать?

    • shs said

      Как вам будет угодно. Всему домену — оно, конечно, проще, но я бы так не делал (в этом случае делегирование будет распространняться на DC и сервера). Я бы создал OU, в которое перенес бы всю структуру ваших OU, содержащих целевые объекты, на которые вы будете делегировать полномочия. И выполнял бы делегирование на уровне этого, вновь созданного, OU.

  6. alex said

    спасибо за скрипт, только он насколько я понял пишет имена в формате domain\user, можно какнибудь сделать чтобы он писал fullname?

  7. alex said

    +1 к карме, спасибо тебе, я не слышал никогда про такие функции

  8. Stanislav said

    Скрипт для записи в атрибут Description объекта-компьютера в AD имени текущего «залогоненного» пользователя + ip

    Import-Module ActiveDirectory
    #$erroractionpreference = «SilentlyContinue» # Раскоментить если хотите пропускать ошибки
    foreach ($comp in (Get-ADComputer -filter * -SearchBase «OU=Отдел,DC=company,DC=local» | select -expand name)) #foreach {$_.name} ))
    { $ping = new-object System.Net.NetworkInformation.Ping
    trap {Write-Verbose $false; » $comp — Ошибка пинга»; continue}
    if ($ping.send($comp).Status -eq «Success»)
    {
    $useroncomp = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $comp).username
    $IP = [System.Net.Dns]::GetHostAddresses(«$comp»)
    $lastuser = Get-ADUser ($useroncomp.split(«\»)[1]) -properties displayname
    Set-ADComputer $comp -Description (($lastuser.DisplayName) + » (» + $IP + «)»)
    }
    else {Write-Host $comp.name «$comp — недоступен»}
    }

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

 
%d такие блоггеры, как: