1 (изменено: holydiver, 2011-03-22 15:29:29)

Тема: VBS: рекурсивный спуск по OU в указанной OU

Есть группа, например "Системные администраторы", у нее в поле "Заметки" написано "title" (это метка), в поле "Описание" написано: "Системный администратор".

Я написал скрипт, который в указанной OU для каждого пользователя проверяет все группы в которые он входит. Если у группы, в которую входит пользователь, в поле "Заметки" есть метка "title", то скрипт этому пользователю в профиль в поле "Должность" пишет то, что у этой группы написано в "Описание".

Суть в том, чтобы всем пользователям заполнить должность.

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

Собственно, вот код:

On Error Resume Next

set objParent = GetObject("LDAP://ou=Пользователи,ou=Новосибирск_nov,ou=домен,dc=domain,dc=local")

for each objUser in objParent
    'Получаем группы непосредственным членом которых является пользователь
    arrMemberOf = objUser.GetEx("memberOf") 
    
    'Просмотр групп безопасности в которые входит пользователь
    For Each Group in arrMemberOf
        set oGroup = GetObject("LDAP://"+Group)
        oGroup.GetInfo
        parse_function(oGroup.Info)
    Next
next

'Функция формирования массива на основе информации в поле "Заметки" для каждой группы
function parse_function(strInfo)
    If strInfo <> "" Then
        str_temp    =     split(strInfo, chr(13)&chr(10))
        str_service    =    str_temp(0)

        temp = objUser.Title
        if temp <> oGroup.Description then
            If str_service = "title" Then 
                objUser.Put "title", oGroup.Description
                objUser.SetInfo
            End If
        Else 'wsh.echo "Equal"
        End if 
    End If
End Function

2

Re: VBS: рекурсивный спуск по OU в указанной OU

holydiver пишет:

... Если у группы, в которую входит пользователь, в поле "Заметки" есть метка "title", то скрипт этому пользователю в профиль в поле "Должность" пишет то, что у этой группы написано в "Описание".
Суть в том, чтобы всем пользователям заполнить должность...

Непонятно, зачем Вы пытаетесь (да ещё рекурсивно) просматривать содержимое контейнеров подразделений.
Раз Вам нужно обработать "учётки" пользователей, являющихся членами определённой группы, то и работайте лишь со списком членов этой группы.
Или я чего-то не понимаю?

holydiver пишет:

... Как мне сделать так, чтобы можно было указать более глобальную OU...

Самый верхний контейнер - это "корень" AD.
Привязка к нему:

Set objContainer = GetObject("LDAP://dc=domain,dc=local")

Если не хотите связываться с константами, то можно так:

Set objRoot = GetObject("LDAP://RootDSE")
Set objContainer = GetObject("LDAP://" & objRoot.Get("DefaultNamingContext"))

3

Re: VBS: рекурсивный спуск по OU в указанной OU

Если указывать "корень" АД, то ничего, собственно, не происходит. Ведь в нем нет вообще никаких пользователей.
Мне надо указать, например, так:

set objParent = GetObject("LDAP://ou=домен,dc=domain,dc=local")

В корне "OU=домен" нет пользователей, в ней есть только другие OU, в которых уже находятся пользователи. А если мне придется вообще по всем пользователям домена пройтись?

ЗЫ, пардон, я видимо опять как-то криво объясняю...

4

Re: VBS: рекурсивный спуск по OU в указанной OU

holydiver, можно изначально работать с «плоским» провайдером, «WinNT:», получая список всех пользователей (если у Вас один домен):
How Can I List All the Users in an NT 4.0 Domain? - Hey, Scripting Guy! Blog - Site Home - TechNet Blogs

Можно извлекать перечень пользователей посредством «ADODB» при помощи провайдера «ADsDSOObject» (ключевое слово тут — «subtree»):
Microsoft Windows 2000 Scripting Guide - Searching Active Directory for User Accounts
Microsoft Windows 2000 Scripting Guide - Modifying Multiple User Accounts by Using the Result Set from a Search
Это, пожалуй, самый эффективный метод, если не требуется последующая модификация (перечень полученных объектов доступен только для чтения, и, если модификация таки требуется — то нужно принудительно «стыковаться» по полученному пути к требуемому объекту, как в примере по последней ссылке).

Так что, коллега Dmitrii совершенно прав насчёт:

Dmitrii пишет:

Самый верхний контейнер - это "корень" AD.
Привязка к нему:

Собственно говоря, когда-то именно из его разъяснений я наконец понял преимущества использования этого метода.

5

Re: VBS: рекурсивный спуск по OU в указанной OU

alexeii, вот оказывается как еще можно... Спасибо большое, ушел изучать что это за зверь ADODB.
И вообще, выпросил у начальства курсы по WSH, а то больше по наитию скрипты пишу, чем с умом %)

6 (изменено: Dmitrii, 2011-03-23 16:57:08)

Re: VBS: рекурсивный спуск по OU в указанной OU

holydiver пишет:

... Мне надо указать, например, так:
set objParent = GetObject("LDAP://ou=домен,dc=domain,dc=local")...

Пример относительной привязки к родительскому контейнеру заданного контейнера:

Set objRoot = GetObject("LDAP://RootDSE")
Set objContainer = GetObject("LDAP://cn=Computers," & objRoot.Get("DefaultNamingContext"))
Set objParent = GetObject(objContainer.Parent)
MsgBox objParent.ADsPath

Ну, и "до кучи" пример рекурсивного просмотра содержимого AD:

'Создание списка отключенных учётных записей пользователей домена
'путём рекурсивного просмотра "дерева" Active Ditectory.
'Отчёт оформляется в виде двух файлов: HTML-страницы и рабочей книги Excel.
'Сценарий ориентирован на работу в графическом режиме.

Dim objRoot, objContainer, objItem
Dim objFS, objFile, objExcel, objWB, objApp
Dim strHTMLText, intCounter, intMaxCells, strTemp, strLog, strBook, strName
Dim arrTemp, arrRecords()
Const strArgToOperation = ""
Const strOperation = "open"
Const intShowMode = 1 'Нормальные настройки положения и размера окна

strLog = "Disabled_Users.htm"
strName = strLog
strBook = "Disabled_Users.xls"
Set objFS = CreateObject("Scripting.FileSystemObject")
strLog = objFS.BuildPath(objFS.GetParentFolderName(WScript.ScriptFullName), strLog)
strBook = objFS.BuildPath(objFS.GetParentFolderName(WScript.ScriptFullName), strBook)
Set objRoot = GetObject("LDAP://rootDSE")
Set objContainer = GetObject("LDAP://" & objRoot.Get("defaultNamingContext"))
Set objRoot = Nothing
intCounter = 0: intMaxCells = 0: strHTMLText = vbNullString
strHTMLText = "<html><title>Отчет об отключенных учетных записях</title><body>" & vbNewLine & _
                "<h2>Отчет об отключенных учетных записях (по состоянию на " & Date & ")" & "</h2>" & vbNewLine
Set objExcel = CreateObject("Excel.Application")
Set objWB = objExcel.Workbooks.Add
objWB.Worksheets(1).Cells(1, 1).Value = "Отчет об отключенных учетных записях (по состоянию на " & Date & ")"
For Each objItem In objContainer
    strTemp = objItem.Class
    If StrComp(strTemp, "organizationalUnit", vbTextCompare) = 0 Or _
        StrComp(strTemp, "container", vbTextCompare) = 0  Then
        Call Get_Members(objItem, objWB, intCounter, intMaxCells, arrRecords)
    End If
Next
Set objItem = Nothing
Set objContainer = Nothing
objWB.Worksheets(1).Cells(intCounter + 4, 1).Value = "Всего " & intCounter  & " отключено."
objWB.Worksheets(1).Columns.AutoFit
objExcel.DisplayAlerts = False
objWB.SaveAs strBook
objExcel.Quit
Set objWB = Nothing
Set objExcel = Nothing
strHTMLText = strHTMLText & "<table width=100% border=1 cellspacing=0 cellpadding=2>" & vbNewLine
For i = 0 To intCounter - 1
    strHTMLText = strHTMLText & "<tr>" & vbNewLine
    arrTemp = Split(arrRecords(i), ",")
    For j = 0 To intMaxCells
        If j <= UBound(arrTemp) Then
            strHTMLText = strHTMLText & "<td>" & Mid(arrTemp(j), 4) & "</td>" & vbNewLine
        Else
            strHTMLText = strHTMLText & "<td>*</td>" & vbNewLine
        End If
    Next
    strHTMLText = strHTMLText & "</tr>" & vbNewLine
Next
strTemp = objFS.GetParentFolderName(WScript.ScriptFullName)
strHTMLText = strHTMLText & "</table>" & "<br>" & vbNewLine
strHTMLText = strHTMLText &  "Всего <b>" & intCounter  & "</b> отключено."
strHTMLText = strHTMLText & "</body></html>"
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objFile = objFS.CreateTextFile(strLog, True)
objFile.Write strHTMLText
objFile.Close
Set objFile  = Nothing
Set objFS = Nothing
'WScript.Echo "Списки созданы."
Set objApp = CreateObject("Shell.Application")
objApp.ShellExecute strName, strArgToOperation, strTemp, strOperation, intShowMode
Set objApp = Nothing
WScript.Quit 0

'=====

Function Get_Members(objOU, objWB, intCount, intCells, arrRec)
Dim objItem, objUser, strTemp, arrTemp

For Each objItem In objOU
    strTemp = objItem.Class
    If StrComp(strTemp, "user", vbTextCompare) = 0 Then
        Set objUser = GetObject(objItem.ADsPath)
        If objUser.AccountDisabled Then
            strTemp = Mid(objUser.ADsPath, 8)
            arrTemp = Split(strTemp, ",")
            If UBound(arrTemp) > intCells Then
                intCells = UBound(arrTemp)
            End If
            ReDim Preserve arrRec(intCount)
            arrRec(intCount) = strTemp
            For i = 0 To intCells
                If i <= UBound(arrTemp) Then
                    objWB.Sheets(1).Cells(intCount + 3, i + 1).Value = Mid(arrTemp(i), 4)
                End If
            Next
            Erase arrTemp
            intCount  = intCount + 1
        End If
        Set objUser = Nothing
    Else
        If StrComp(strTemp, "organizationalUnit", vbTextCompare) = 0 Or _
            StrComp(strTemp, "container", vbTextCompare) = 0 Then
            Call Get_Members(objItem, objWB, intCount, intCells, arrRec)
        End If
    End If
Next
Set objItem = Nothing
End Function

7

Re: VBS: рекурсивный спуск по OU в указанной OU

Dmitrii, угу, спасибо, на досуге попробую разобраться. На первый взгляд, ничего сложного нет

8

Re: VBS: рекурсивный спуск по OU в указанной OU

Не подскажите как быть если вместо AD связка SAMBA+LDAP. Скрипты для AD не работают, напрямую. Но так как каталог LDAP (Open LDAP) может есть способ к нему достучатся. Провайдер WinNT работает, но мало методов у него. Хотелось бы научиться "читать" существующий каталог используя скрипты. Например нужно узнать к какому отделу (OU) относится пользователь и атрибуты самого пользователя.

9

Re: VBS: рекурсивный спуск по OU в указанной OU

2vv пишет:

... Провайдер WinNT работает...

Приведите, пожалуйста, соответствующий пример сценария.

10

Re: VBS: рекурсивный спуск по OU в указанной OU

используйте запрос

Я конечно далек от мысли... (с)

11 (изменено: 2vv, 2012-06-14 22:49:28)

Re: VBS: рекурсивный спуск по OU в указанной OU

Вот пример из сети...

 Sub ListConnectedComputers( strDomain )
    Dim objPDC
    Set objPDC = getobject("WinNT://" & strDomain )
    objPDC.filter = Array("Computer")
    For Each objComputer In objPDC
    WScript.Echo objComputer.Name
    Next
End Sub
Dim strDomain
Do
    strDomain = inputbox( "Please enter a domainname", "Input" )
Loop until strDomain <> ""
ListConnectedComputers( strDomain )

Есть похожие примеры и с LDAP провайдером. То есть вывести список всех OU и тп. Но никак не пойму как читать атрибуты у пользователей.

12

Re: VBS: рекурсивный спуск по OU в указанной OU

атрибуты читаются так же

Я конечно далек от мысли... (с)

13

Re: VBS: рекурсивный спуск по OU в указанной OU

Можно пример. Например у пользователя есть атрибут mail. Путь у него такой  uid=vpetrov,ou=users,dc=domain,dc=com .

14

Re: VBS: рекурсивный спуск по OU в указанной OU

var Пользователь,Пароль,Домен,Стр,Контроллер,Отбор,Провайдер,ТЗ,АДСИ,ТекстЗапроса;
try
{
    WScript.StdOut.Write(0);
}
catch(e)
{
    new ActiveXObject("WScript.Shell").Run('cscript.exe "'+WScript.ScriptFullName+'"');
    WScript.Quit();
}
ТЗ=new Array();
АДСИ=new ActiveXObject("ADSystemInfo");
Контроллер=АДСИ.GetAnyDCName();
Домен=АДСИ.DomainDNSName;
Пользователь="администратор@" + Домен;
Пароль="СуперПароль";
ДСО=GetObject("LDAP:");
Корень=ДСО.OpenDSObject("LDAP://"+Контроллер+"/RootDSE", Пользователь, Пароль,1);
ТекстЗапроса="<LDAP://";//+Контроллер;
if (!Домен)
{
    Провайдер="Provider=ADSDSOObject;User Id="+Пользователь+"@"+Домен+";Password="+Пароль;
    ТекстЗапроса=ТекстЗапроса+Стр+">";
}
else
{
    Провайдер="Provider=ADSDSOObject;";
    ТекстЗапроса=ТекстЗапроса+Корень.Get("defaultNamingContext")+">";
};

//Отберем только тип пользователи и только начинается логин вин200 на букову G
Маска="gi*";
Отбор=";(&(&(objectClass=User)(!objectClass=Computer))(sAMAccountName=" + Маска + "));AdsPath;subTree";
//Отбор=";(&(objectClass=Group)(sAMAccountName=" + Маска + "));AdsPath;subTree";
//Отбор=";(&(objectClass=organizationalUnit)(name=Сбыт));AdsPath;subTree";
ТекстЗапроса=ТекстЗапроса+Отбор;

Соединение = new ActiveXObject("ADODB.Connection");
Соединение.Open(Провайдер);
Записи=Соединение.Execute(ТекстЗапроса);
Сч=-1;
while (!Записи.EOF)
{
    Сч++;
    ТЗ[Сч]=new Object();
    ТЗ[Сч]['ADSPath']=Записи.Fields(0).Value;

    ЗаписиОбъекта=GetObject(Записи.Fields(0).Value);
    ЗаписиОбъекта.GetInfo();
    while (true)
    {
        try{Поле=ЗаписиОбъекта.Next()}catch(e){break}
        ТЗ[Сч][Поле.Name]=ЗаписиОбъекта.Get(Поле.Name);
    };
    Записи.MoveNext();
};
for (Сч in ТЗ)
    for (Кол in ТЗ[Сч])
    {
        try{WScript.Echo(Кол,ТЗ[Сч][Кол])}catch(e){}
    }
WScript.StdOut.Write('\n*********************\nPress Enter...');
WScript.StdIn.ReadLine();
Я конечно далек от мысли... (с)

15

Re: VBS: рекурсивный спуск по OU в указанной OU

Спасибо, но честно говоря не очень понятно. Как это без русских слов-то будет выглядеть ?  К тому же var в vbscript  нет.

16

Re: VBS: рекурсивный спуск по OU в указанной OU

2vv пишет:

К тому же var в vbscript  нет.

Сие похоже на JScript.

17

Re: VBS: рекурсивный спуск по OU в указанной OU

2vv, глядя на пример из сообщения #11, не могут осмыслить фразу "... Скрипты для AD не работают, напрямую..." из сообщения #8, т.к. этот сценарий ничем не отличается от тех, что используются для работы с AD в "окошках".

18

Re: VBS: рекурсивный спуск по OU в указанной OU

GetObject("LDAP://rootDSE") - вот это вне AD  , как я понимаю, не работает.  А я имею дело со связкой Samba+LDAP (Open LDAP)

19 (изменено: alexii, 2012-06-19 23:36:32)

Re: VBS: рекурсивный спуск по OU в указанной OU

2вв это не зависит от источника
а так пингвинофилам не помогаю, ибо оные удалено злобным модератором

управляющие, можно пост понимать как нарушающий, а можно "понять, простить и отпустить"

Что было явно лишним — я убрал.

Я конечно далек от мысли... (с)

20 (изменено: smaharbA, 2012-06-19 23:51:21)

Re: VBS: рекурсивный спуск по OU в указанной OU

для 2вв, если очень туга для вин
ldifde и масса дс и прочих средств штатных
для никс лдапсёрч и нет

и не зависит от источника

Я конечно далек от мысли... (с)

21

Re: VBS: рекурсивный спуск по OU в указанной OU

Да я и не пингвинофил. И не я делал такой домен (Samba+LDAP). Да и если честно функционала такой связки хватает. Просто неудобно  LDAP браузером пользоваться.