Active Directory w skryptach ADSI część 2 – tworzenie obiektów w katalogu AD

wersja 1.0

W tej części zajmiemy się zagadnieniem równie prostym (jak się okaże) jak przeszukiwanie katalogu, a mianowicie tworzeniem obietków w ramach katalogu AD i modyfikowaniu ich właściwości po utworzeniu. Jako przykłady posłużą nam najczęściej tworzone obiekty w ramach AD a więc:

  • konto użytkownika,
  • grupa użytkowników,

rozszerzone o elementy zarządzania konfiguracją skrzynek Exchange Server. Przedstawione zostaną podstawowe zagadnienia związane z tworzeniem obiektów w ramach AD z zastosowaniem interfejsu ADSI wraz z komentarzami.

Wszystkie przedstawione w artykule przykład na jego potrzeby były testowane na serwerze Windows 2003 Server Standard Edition oraz Exchange 2003 Server Standard, jednakże powinny one działać bez potrzeb modyfikacji również dla Windows 2000 Server / Exchange 2000 Server. W przypadku systemu Windows 2000 zalecane jest uaktualnienie Windows Scripting Host do wersji 5.6.
W przedstawianych przykładach zastosowane zostaną metody dostępu do danych katalogu opisane w pierwszej części dotyczącej metod dostepu do katalogu do której lektury zachęcam.

Utworzenie konta użytkownika Konto użytkownika jest chyba najczęściej tworzonym obiektem w ramach katalogu AD. ZakÅ‚adanie kont poprzez interfejs GUI jest proste ale maÅ‚o użyteczne w przypadku gdy czynnoÅ›ci tej dokonujemy czÄ™sto a do utworzenia mamy wiele kont. W takim przypadku z pomocÄ… przychodzÄ… administratorowi różne metody zautomatyzowania tego typu operacji, takie na przykÅ‚ad jak impot danych za pomocÄ… poleceÅ„ ldifde czy cvsde. Jednak to co “administratorzy” lubiÄ… najbardziej to różnego rodzaju skrypty, tak wiÄ™c i zakÅ‚adanie kont użytkowników można w prosty sposób zautomatyzować z zastosowaniem interfejsu dostÄ™pu do danych katalogu – ADSI.

Skrypt mający założyć konto użytkownika rozpoczynamy od utworzenia ścieżki dostępu do kontenera katalogu w którym ma zostać utworzone konto w sposób opisany w poprzednim artykule. Dostep do obiektu konteneru uzyskujemy na podstawie poświadczeń użytkownika uruchamiającego skrypt poprzez wywołanie metody GetObject ze ścieżką LDAP jako paramterem.
'Tworzymy ścieżkę dostępny w katalogu do kontenera w którym utworzone zostanie konto
strDestOU = "OU=Ksiegowosc"

Set rootDSE = GetObject("LDAP://rootDSE")
strDomain = rootDSE.Get("defaultNamingContext")

strDestDSPath = strDestOU & "," & strDomain
'pobieramy obiekt OU za pomocÄ… metody GetObject
Set objDestOU = GetObject("LDAP://"& strDestDSPath)

NastÄ™pnie w obiekcie OU do którego uzyskalismy poÅ‚Ä…czenie tworzymy nowy obiekt – konto użytkownika – wywoÅ‚ujÄ…c metodÄ™ Create. Jako atrybut wywoÅ‚ania podajemy typu tworzonego obiektu (w naszym przypadu user) oraz nazwÄ™ Common Name (CN) obiektu w katalogu. przykÅ‚adowe wywoÅ‚anie przedstawione jest poniżej:

'utworzenie obiektu klasy "User"
'jako parametr wywolania konieczne jest okreslenie unikalnej nazwy CN dla obiektu
Set objUser = objDestOU.Create("User","CN=JanKowalski)

Powyższy fragment kodu tworzy w katalogu obiekt klasy “user”, jednak aby obiekt ten byÅ‚ użyteczny z punktu widzenia użytkownika i administora warto zaraz po jego zaÅ‚ożeniu ustawić kilka z jego atrybutów. WartoÅ›ci poszczególnym atrybutom obiektu nadajemy z zastosowaniem metody Put. Po ustawieniu odpowiednich danych zapisujemy wÅ‚aÅ›ciwoÅ›ci atrybutu do katalogu poprzez wywoÅ‚anie dla obiektu metody SetInfo:

With objUser
'nazwa logowania konta
.Put "samAccountName", "JanKowalski"

'podstawowy UPN dla konta
.Put "userPrincipalName", "JanKowalski@" & strDomain

'Dane opisu konta użytkownika - imię oraz nazwisko
.Put "givenName", "Kowalski"
.Put "sn", "Jan"

'Nazwa pod ktora konto bedzie widoczne w katalogu (GUI)
.Put "displayName", strLastName & " " & strFirstName

.Put "homeDrive", "Z:"
.Put "homeDirectory", "\\FSSever\Users\JanKowalski"

'zapisujemy dotychczasowe zmiany
.SetInfo

'okreslamy haslo uzytkownika
.SetPassword "bardzotrudnehaslo"
.SetInfo

'ustawiamy wymaganie zmiany hasla przy pierwszym logowaniu
.Put "pwdLastSet", 0

'upewniamy sie ze konto jest aktywne
.AccountDisabled = False
.SetInfo
End With

InformacjÄ™ o wszystkich atrybutach obiektu do których mamy dostÄ™p dla obiektu typu “user” w katalogu AD można uzyskać listujÄ…c te atrybuty za pomoca skryptu, przeglÄ…dajÄ…c jego wÅ‚aÅ›ciwoÅ›ci za pomocÄ… konsoli ADSI Edit lub (co może być najszybsze i najwygodniejsze) korzystajÄ…c z witryny MSDN.

Kompletny kod skryptu zakładającego konto użytkownika w wybranym OU dostępny jest tutaj.

Proces pobierania danych niezbędnych do utworzenia konta można w prosty sposób zautomatyzować poprzez przygotowanie danych wcześniej w pliku (np. tekstowym lub arkuszu Excel) a następnie wczytanie ich w skrypcie. Poniżej przedstawiony został fragment skryptu wczytującego dane wejściowe do założenia konta z pliku tekstowego o nastepującym formacie:

login;Imie;Nazwisko;haslo

Pierwszym krokiem jest utworzenie obiektu FileSystemObject i odczytanie pliku z dysku:

'sciezka dostepu do pliku z danymi o kontach
strFilePath = "plik.txt"

'Tworzymy obietk typu FileSystemObject
Set oFs = CreateObject("Scripting.FileSystemObject")
'otwieramy plik do odczytu tworzac tym samym obiekt pliku
Set oFile = oFs.OpenTextFile( strFilePath )

'Odczytujemy zawartosc pliku do zmiennej tekstowej
struserAccounts = oFile.ReadAll()
'zamykamy plik
oFile.Close
'niszczymy obiekty zwiazane z obsluga plikow
Set oFile = Nothing
Set oFS = Nothing

NastÄ™pnie pobranÄ… zawartość pliku musimy przetworzyć do formatu tablicy z pożądanymi dla nas elementami korzystajÄ…c z funkcji Split. pierwszym krokiem jest podziaÅ‚ pliku na kolejne linie tekstu z danymi użytkownikami używajÄ…c jak delimitera znaku koÅ„ca linii (staÅ‚a vbCRLF). Linie te nastÄ™pnie podzielone zostanÄ… na poszczególne dane poprzez kolejne wywoÅ‚anie funkcji Split tym razem ze znakiem Å›rednika (‘;’) jako delimitera. Proces ten przedstawiony zostaÅ‚ poniżej na przykÅ‚adzie skryptu:

'Pobieramy obiekt w ktorym zakladani beda uzytkownicy
strDestOU = "OU=Ksiegowosc"
Set rootDSE = GetObject("LDAP://rootDSE")
strDomain = rootDSE.Get("defaultNamingContext")
strDestDSPath = strDestOU & "," & strDomain
Set objDestOU = GetObject("LDAP://"& strDestDSPath)

'podzial wczytanej zawartości pliku na poszczególne linie
arrUserDate = Split (struserAccounts, vbCRLF )

'Sprawdzamy czy w tabeli znajdujÄ… siÄ™ jakieÅ› elementy
'Funkcja Ubound określa górny zakres indeksów elementów tablicy
If UBound(arrUserDate) > 0 Then
'dla kazdego elementu wykonujemy podzial danych na poszczegolne elementy oraz utworzenie uzytkownika
for each arrUser in arrUserDate
arrUserDetails = Split (arruSer, ";" )

'tworzymy konto uzytkownika jako dane podstawiajac kolejne elementy tablicy
Set objUser = objDestOu.Create("user", "CN=" & arrUserDetails(0) )
With objUser
.Put "samAccountName", arrUserDetails(0)
.Put "userPrincipalName", arrUserDetails(0) & "@" & strDomain
.Put "givenName", arrUserDetails(2)
.Put "sn", arrUserDetails(1)
.Put "displayName", arrUserDetails(2) & " " & arrUserDetails(1)
.SetInfo
.SetPassword arrUserDetails(3)
.SetInfo
.Put "pwdLastSet", 0
.AccountDisabled = False
.SetInfo
End With
Set objUser = Nothing
next
End IF

Kompletny kod skryptu zakładającego konto użytkownika w wybranym OU na podstawie danych z pliku tekstowego dostępny jest tutaj.

Utworzenie nowej grupy użytkowników

Utworzenie grupy użytkowników nie różni siÄ™ zasadniczo od utworzenia w ramach wybranego kontenera obiektu użytkownika, obiekt grupy tworzony jest jako “liść” (leaf) wybranego kontenera w analogiczny sposób jak obiekt użytkownika, zmienia siÄ™ tylko typ tworzonego obiektu. Utworzenie obiektu grupy prezentuje poniższy fragment skryptu (komentarze w skrypcie):

'Pobieramy obiekt OU w ktorym utworozna zostanie grupa
strDestOU = "OU=IT,DC=W2k,DC=local"
Set objDestOU = GetObject("LDAP://"& strDestOU)

'utworzenie obiektu klasy "Group"
'jako parametr wywolania konieczne jest okreslenie unikalnej nazwy CN dla obiektu
Set objGroup = objDestOU.Create("Group","CN=Administratorzy-Sieci")

'ustawiamy dodatkowe wlasciwosci obiektu
objGroup.Put "samAccountName" , "AdministratorzySieci"
objGroup.Put "Description", "Administratorzy urzadzen sieciowych"

Po utworzeniu grupy użytkowników konieczne jest jednak określenie jej zakresu i typu. W Active Directory występują zasadniczo dwa typu grup:

  • dystrybucyjne (distribution
  • zabezpieczeÅ„ (security).

Dodatkowo dla każdej grupy definiowany jest jej zakres, i tak mamy nastepujące grupy:

  • lokalne domenowe (Local domain)
  • globalna (global)
  • uniwersalna (universal).

We właściwościach obiektu grupy typ oraz zakres grupy definiowany jest poprzez umieszczenie w wartości atrubut groupType obiektu grupy odpowiedniej kombinacji typu grupy oraz jej zakresu. Wartości deifiniujące odpowiedni typ oraz zakres grupy przedstawione zostały w poniższej tabeli:

Typ grupy
Typ Wartość
dystrybucyjne
zabezpieczeń -2147483648
Zakres grupy
Zakres Wartość
lokalne domenowe 1
globalna 2
uniwersalna 8

Aby utworzyć grupÄ™ o okreÅ›lonym zakresie i typie konieczne jest poÅ‚Ä…czenie operacjÄ… ‘OR’ odpowiednich wartoÅ›ci. PrzykÅ‚ad ustawienia rodzaju grupy znajduje siÄ™ poniżej:

'definicja stalych dla poszczegolnego typu i zakresu grup
Const ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP = 4
Const ADS_GROUP_TYPE_GLOBAL_GROUP = 2
Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = 8
Const ADS_GROUP_TYPE_SECURITY_ENABLED = -2147483648

'Lokalna domenowa grupa zabezpieczen
objGroup.Put "groupType", ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED
objGroup.SetInfo

'zapisujemy utworzony wlasnie obiekt grupy
objGroup.SetInfo

Jeżeli nie określimy wprost typu i zakresu grupy domyślnie tworzona jest globalna grupa zabezpieczeń.
Kompletny kod skryptu zakładającego grupę użytkowników dostępny jest tutaj.

Grupa staje siÄ™ użyteczna w chwili gdy zawiera odpowiednie obiektu, tak wiÄ™c możemy bezpoÅ›rednio po utworzeniu grupy dodać do niej odpowiednie obiekty. Aby dodać użytkownika do grupy musimy znać wartość jego atrybutu distinguishedName (DN) czyli nazwy wyróżniajÄ…cej użytkownika w katalogu. NastÄ™pnie wartość tÄ… dopisujemy do wartoÅ›ci atrybutu “member” wybranego obiektu grupy wywoÅ‚ujÄ…c metodÄ™ PutEx. Pierwszym etapem jest pobranie odpowiedniego obiektu grupy:

'stala okreslajaca typ zapisu do wartosci - dopisywanie do zawartosci atrybutu
Const ADS_PROPERTY_APPEND = 3

'pobieramy obiekt grupy poprzez wywolanie metody GetObject
Set objGroup = GetObject("LDAP://CN=Administratorzy,OU=IT,DC=w2k,DC=local")

Następnie określamy DN użytkownika bądź to jako stałą znakową lub też wybierając dynamicznie na podstawie zapytania do katalogu:

'DN użytkownika 1 zdefiniowana jako stała
strUserDN = "CN=Administrator1,OU=IT,DC=W2k,DC=local"

'dopisujemy użytkownika do listy członków grupy
objGroup.PutEx ADS_PROPERTY_APPEND, "member", Array(strUserDN)

'zapisujemy wlasnosc grupy
objGroup.SetInfo

Set objGroup = Nothing

Lista użytkowników dopisywanych do grupy może być tworzona dynamicznie na podstawie przeszukiwania katalogu. Aby dodać do wybranej grupy zabezpieczeń na przykład wszystkich użytkowników wybranego OU można posłużyć się następującym fragmentem skryptu:

'pobieramy docelowy obiekt grupy
Const ADS_PROPERTY_APPEND = 3
Set objGroup = GetObject("LDAP://CN=Administratorzy,OU=IT,DC=w2k,DC=local")

'pobieramy zrodlowe OU
Set objSrcOU = GetObject("LDAP://CN=IT,DC=W2K,DC=local")
'wybieramy z OU obiekty typu uzytkownik
objSrcOU.Filter = Array("user")

'dodajemy kolejnych uzytkownikow do wybranej grupy
for each objUser in objSrcOU
objGroup.PutEx ADS_PROPERTY_APPEND, "member", Array(objUser.distinguishedName)
objGroup.SetInfo
Next
Set objGroup = Nothing
Set objSrcOU = Nothing

Kod skryptu dodającego użytkowników do grupy dostępny jest poniżej:

Uzupełnienie konta użytkownika i grupy dystrybucyjnej o atrybuty Exchange

Skrypt stosujący ADSI oraz inne interfejsy można również zastosować do zarządzania skrzynką pocztową dla konto użytkownika w ramach serwera Exchange 2000/2003 a jako że infrastruktura katalogu Active Directory często idzie w parze z wdrożeniem usług Exchange można również zadanie tworzenia skrzynek Exchange przełożyć na skrypt. Zarządzanie skrzynkami Exchange poprzez skrypty możliwe jest na systemach w których zainstalowana jest biblioteka CDOEXM stanowiąca interfejs zarządzania dla serwera Exchange. Biblioteka ta obecna jest w systemach w których zainstalowane są narzędzia administracyjne Exchange, i jest to (instalacja narzędzia administracyjnych) najszybszy sposób przygotowania systemu do działania w nim skryptów zarządzających danymi Exchange Server.

Skrypt zakÅ‚adajÄ…cy skrzynkÄ™ pocztowÄ… Exchange jest bardzo prosty (jak wszystko z ADSI 🙂 ) z tego wzglÄ™du przedstawiam go poniżej bez dodatkowego wstÄ™pu wraz z komentarzami:

'Nazwa DN do obiektu uzytkownika dla ktorego utworzona zostanie skrzynka
strUserDN = "CN=Jankowalski,OU=IT,DC=w2k,DC=Local"

'pobranie obiektu uzytkownika i przypisanie go do zmiennej
Set objUser = GetObject ("LDAP://"& strUserDN )
Set objMailbox = objUser

'sciezka do skladnicy danych serwera Exchange w ramach ktorej zalozona
'zostanie skrzynka uzytkownika (wyjasnienie ponizej skryptu)
strExchangePath = "CN=Mailbox Store (VIRTUALSEC),CN=First Storage Group," &_
"CN=InformationStore,CN=VIRTUALSEC,CN=Servers,CN=First Administrative Group,"&_
"CN=Administrative Groups,CN=W2K,CN=Microsoft Exchange,CN=Services," &_
"CN=Configuration,DC=w2k,DC=local"

'Wywolanie metody CreateMailbox - jako argument sciezka LDAP do skladnicy danych
objMailbox.CreateMailbox "LDAP://" & strExchangePath
'zapisanie zmian
objMailbox.SetInfo

'obsluzenie ewentualnego bledu przy zakladaniu skrzynki z wykorzystaniem obiektu Err
If Err.Number <> 0 Then
Wscript.echo "Blad zakladania skrzynki"
Else
Wscript.Echo "Skrzynka zostala zalozona"
End If

Jak widać sam skrypt jest banalnie prosty pojawia siÄ™ w nim jednak element wymagajÄ…cy wyjaÅ›nienia – sciezka dostÄ™pu LDAP do skladnicy danych Exchange. Jak wiadomo konfiguacja Exchange 2000/2003 przechowywana jest w katalogu Active Directory. Jak również wiadomo serwery te mogÄ… posiadać wiÄ™cej niż jednÄ… grupÄ™ skÅ‚adowania danych w ramach których mogÄ… istnieć zasoby skrzynek pocztowych użytkowników, Åšcieżka przechowywana w skrypcie w zmiennej strExchangePath wskazuje po prostu Å›cieżkÄ™ w AD w partycji konfiguracji do skÅ‚adnicy danych w ramach której skrzynka zostanie utworzona. ÅšcieżkÄ™ ta zależy od konkretnej konfiguracji serwera Exchange (w szczególnoÅ›ci nazwy organizacji exchange, nazwy grupy administracyjnej itp) i może być w prosty sposób ustalona na przykÅ‚ad poprzez przystawkÄ™ adsiedit.msc, w której to otwieramy partycjÄ™ konfiguracji i nawigujemy poprzez usÅ‚ugi i serwery Exchange do interesujÄ…cego nas skÅ‚adu danych. Konsola ADSIEdit z otwartÄ… Å›cieżka z przedstawionego powyżej skryptu znajduje siÄ™ na poniższym rysunku.

ADSIEdit

To samo zadanie można zrealizować w troche inny sposób z zastosowaniem klasy CDO.Person i wchodzącego w jej skład interfejsu IMailBox. Jest to inne podejście do wykonania tego samego zadania, w niektórych przypadkach może być ono bardziej wygodne. Przykład utworzenia skrzynki pocztowej z zastosowaniem klasy CDO.Person znajduje się wraz z komentarzem poniżej:

'Nazwa DN do obiektu uzytkownika dla ktorego utworzona zostanie skrzynka
strUserDN = "CN=Jankowalski,OU=IT,DC=w2k,DC=Local"

'tworzymy instancje obiektu klasy CDO.Person
Set objPerson = CreateObject("CDO.Person")

'Otwieramy zrodlo danych jakim jest obiekt uzytkownika w katalogu
'poslugujac sie w tym celu nazwa DN tego obiektu
objPerson.DataSource.Open "LDAP://" & strUserDN , , 3

'pobieramy interfejst IMailBoxStore obiektu
Set objMailbox = objPerson.GetInterface("IMailboxStore")

'sciezka do skladnicy danych serwera Exchange w ramach ktorej zalozona
'zostanie skrzynka uzytkownika (wyjasnienie ponizej skryptu)
strExchangePath = "CN=Mailbox Store (VIRTUALSEC),CN=First Storage Group," &_
"CN=InformationStore,CN=VIRTUALSEC,CN=Servers,CN=First Administrative Group,"&_
"CN=Administrative Groups,CN=W2K,CN=Microsoft Exchange,CN=Services," &_
"CN=Configuration,DC=w2k,DC=local"

'Wywolanie metody CreateMailbox - jako argument sciezka LDAP do skladnicy danych
objMailbox.CreateMailbox "LDAP://" & strExchangePath

'zapisujemy zmiany w zrodle danych
objPerson.DataSource.Save

'obsluzenie ewentualnego bledu przy zakladaniu skrzynki z wykorzystaniem obiektu Err
If Err.Number <> 0 Then
Wscript.echo "Blad zakladania skrzynki"
Else
Wscript.Echo "Skrzynka zostala zalozona"
End If

Kod skryptu tworzącego skrzynki Exchange dostępny jest poniżej:

W podobny sposób można również usuwać skrzynki Exchange czy też dokonywać zmian ich położenia pomiędzy poszczególnymi składnicami danych czy serwerami Exchange.

Uaktualnienie grupy dystrybucyjnej utworzonej w ramach AD o atrybuty serwera Exchange jsst zadaniem o wiele trwialniejszym niż założenie skrzynki użytkownika, dlatego też pozwolę sobie przedstawić tylko gotowy skrypt z minimalnym komentarzem:

'pobieramy obiekt grupy dystrybucyjnej
Set objGroup=GetObject("LDAP://CN=Administratorzy-Sieci,OU=IT,DC=W2k,DC=local")

'rozszerzamy grupę o funkcjonalność serwera Exchange
objGroup.Mailenable

'zapisujemy zmiany w obiekcie
objGroup.SetInfo

Powyższy przykład również wymaga zainstalowanej w systemie biblioteki CDOEXM.

Podsumowanie

W artykule zostaÅ‚y przedstawione podstawowe zagadnienia zwiÄ…zane z zakÅ‚adaniem obiektów w katalogu AD z zastosowaniem nterfejsu ADSI rozszerzone o komentarze oraz kilka przykÅ‚adów pÅ‚ynÄ…cych “z życia administratora”. OczywiÅ›ci możliwoÅ›ci interfejsu ADSI sÄ… o wiele szersze co postaram siÄ™ przedstawić w kolejnych artykuÅ‚ach (mam nadziejÄ™ że powstanÄ…), zachÄ™cam jednak do samodzielnego eksperymentowania z przedstawionymi w obu częściach tej serii elementami. KorzystajÄ…c nawet z podstawowej możliwoÅ›ci wyszukiwania i tworzenia danych w AD można znacznie uÅ‚atwić wiÄ™kszość typowych prac administratora usÅ‚ug katalogowych Active Directory.