Centrum Skryptóe - Active Directory

Jak określić katalog domowy dla wszystkich wyłączonych kont użytkowników w Active Directory?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak określić katalog domowy dla wszystkich wyłączonych kont użytkowników w Active Directory?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Jak określić katalog domowy dla wszystkich wyłączonych kont użytkowników w Active Directory?

-- DB

Cześć Skrypciarze! Odpowiedź

Cześć, DB. Wczoraj piszący te słowa Skrypciarz oglądał telewizję i zobaczył reklamę urządzenia, które wyręcza cię w „trudnej i męczącej czynności” mieszania jajek na jajecznicę. Prawdę mówiąc, Skrypciarz piszący te słowa nigdy nie uważał mieszania jaj za szczególnie męczące. Jest ono jednak dużym problemem dla wielu ludzi. A przynajmniej było, dzięki nowemu urządzeniu. Wystarczy teraz wziąć jajo, wbić w nie to coś przypominającego igłę i włączyć mieszalnik. Gdy rozbijecie jajko voila! Będzie już rozmieszane! Czy technika nigdy nie przestanie nas zadziwiać?

W każdym razie, DB, prawie nie odpowiedzieliśmy na twoje pytanie; w zasadzie to zastanawialiśmy się, czy w ogóle będziemy jeszcze odpowiadać na jakieś pytania. Na pewno rozumiesz, dlaczego. W końcu skrypt określający katalog domowy dla wszystkich wyłączonych kont użytkowników w Active Directory nie wygląda imponująco w porównaniu z automatycznym mieszalnikiem do jajek. Ale przedstawienie musi trwać. Następujący skrypt nie rozmiesza za was jajek, ale może komuś do czegoś się przyda:

On Error Resume Next



Set objConnection = CreateObject("ADODB.Connection")

Set objCommand = CreateObject("ADODB.Command")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"

Set objCommand.ActiveConnection = objConnection



objCommand.Properties("Page Size") = 1000



objCommand.CommandText = _

    "<LDAP://dc=fabrikam,dc=com>;" & _

    "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=2));" & _

            "Name,homeDirectory;Subtree"

Set objRecordSet = objCommand.Execute



objRecordSet.MoveFirst



Do Until objRecordSet.EOF

    Wscript.Echo objRecordSet.Fields("Name").Value

    Wscript.Echo objRecordSet.Fields("homeDirectory").Value

    Wscript.Echo 

    objRecordSet.MoveNext

Loop

Jak zwykle, nie będziemy omawiać każdego wiersza skryptu z osobna. Jeśli potrzebujecie kursu pisania skryptów wyszukiwania w Active Directory, polecamy naszą dwuczęściową serię Tales from the ScriptDude, Where’s My Printer? Przeznaczymy jednak minutę lub dwie na przyjrzenie się kwerendzie, której używamy w tym skrypcie, kwerendzie, która pobiera wartości atrybutów Name i homeDirectory dla wszystkich użytkowników, których konta zostały wyłączone:

objCommand.CommandText = _

    "<LDAP://dc=fabrikam,dc=com>;" & _

    "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=2));" & _

            "Name,homeDirectory;Subtree"

Dlaczego ta kwerenda tak wygląda? Cóż, aby określić czy konto użytkownika zostało wyłączone, musimy sprawdzić wartość atrybutu userAccountControl. Jak się okazuje, userAccountControl to atrybut maski bitów, atrybut, który rzeczywiście zawiera liczbę właściwości i ich wartości. (Listę tych właściwości znaleźć można w artykule Active Directory Schema Reference na MSDN.) Jako że userAccountControl jest atrybutem maski bitów, nie możemy użyć standardowej kwerendy SQL (n.p., “Select Name, homeDirectory From ….”) w celu pobrania informacji opartych o ten atrybut. To po prostu nie zadziała. Zamiast tego musimy użyć składni kwerendy LDAP. I dlatego właśnie ta kwerenda wygląda dziwnie.

Bez zagłębiania się w szczegóły (które znajdziecie w naszym webcaście o pisaniu skryptów wyszukiwania w Active Directory) oto wyjaśnienie poszczególnych części kwerendy (zauważcie, że są one rozdzielona średnikami):

<LDAP://dc=fabrikam,dc=com>. Tę część zapewne sami zrozumiecie: to po prostu domena, w której będziemy szukać.

(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=2)). To, wierzcie w to lub nie, jest nasz filtr kwerendy, część, gdzie określamy kryteria wyszukiwania. W tym wypadku mamy dwa kryteria, które muszą zostać spełnione: obiekt musi mieć objectCategory równe user, i ustawioną flagę wyłączonego konta (która ma wartość 2). Jasne, nie jest to całkiem oczywiste gdy patrzycie na kwerendę, ale to prawda. Na przykład 1.2.840.113556.1.4.803 to “LDAP bit matching rule,” coś, co jest w zasadzie równe słowu kluczowemu AND w boole’owskim poleceniu takim jak If objUserAccountControl AND 2.

Dlaczego więc ludzie od kwerendy LDAP po prostu nie użyją słowa AND? Nie wiemy; możemy tylko spekulować, że wtedy nie byłaby to już LDAP bit matching rule gdyby tego nie zrobili. Ale nie martwcie się o to; po prostu użyjcie składni dokładnie tak, jak wam pokazaliśmy i wszystko będzie w porządku.

Co ciekawe, ampersand (&) na początku ciągu filtra po prostu łączy dwie części naszej kwerendy: tę, że objectCategory musi równać się user i tę, że musi być ustawiona odpowiednia flaga w userAccountControl. Więcej informacji o kwerendach LDAP można znaleźć w naszym webcaście. Jeśli nie chcecie czytać o tym więcej, wszystko w porządku. W takim wypadku po prostu skopiujcie pokazany tu kod i zmodyfikujcie go, jeśli będziecie chcieli użyć kwerendy korzystającej z innej właściwości, którą można znaleźć w userAccountControl. Na przykład, w przypadku użytkwonika, który ma hasło, które nigdy nie wygasa, w userAccountControl włączona będzie flaga o wartości 65536. Oznacza to, że można wyszukać go (i innych kont o niewygasających hasłach) przy użyciu tego filtra:

(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=65536))

Zmieniliśmy jedynie szukaną wartość, używając 65536 zamiast 2 z pierwotnego filtra.

Uwaga. Mogliście zauważyć, że nasza kwerenda LDAP wydaje się trochę ściśnęta; na przykład mamy objectCategory=user zamiast ładniejszego: objectCategory = user ze spacjami. Czy to ważne? Zaskoczymy was, ale tak. Jeśli umieścicie spacje między atrybutem, znakiem równości, a wartością (n.p., objectCategory = user) wasz skrypt nie będzie działał. Innymi słowy, ściśnijcie wszystko tak mocno, jak tylko się da.

Name,homeDirectory. Ten fragment filtra trochę łatwiej zrozumieć: to po prostu lista wartości właściwości, które ma zwracać nasz skrypt. Warto zauważyć, że oddzieliliśmy poszczególne wartości przecinkami. Jak już wspomnieliśmy, średnika używamy do oddzielenia poszczególnych części filtra.

Subtree. To zakres wyszukiwania, który po prostu mówi skryptowi, aby zaczął wyszukiwanie w katalogu głównym domeny, a następnie przeszukał każdy kontener w tej domenie.

Tak, to jest szalone. Jednakże to rzeczywiście działa, a gdy zdefiniujemy kwerendę, musimy jedynie wywołać metodę Execute aby rozpocząć wyszukiwanie i otrzymać zbiór rekordów zawierajacyh Name i homeDirectory dla wszystkich wyłączonych kont użytkowników. Gdy tylko będziemy mieli ten zbiór rekordów, możemy utworzyć pętlę Do Until, która przejdzie przez otrzymane dane, wyświetlając odpowiednie wartości dla każdego konta:

Do Until objRecordSet.EOF

    Wscript.Echo objRecordSet.Fields("Name").Value

    Wscript.Echo objRecordSet.Fields("homeDirectory").Value

    Wscript.Echo 

    objRecordSet.MoveNext

Loop

Należy zwrócić tu uwagę na dwie rzeczy. Po pierwsze, na składnię odwoływania się do elementu zbioru rekordów:

objRecordSet.Fields("Name").Value

Jeszcze raz, nie martwcie się, dlaczego. Po prostu skopiujcie kod taki, jakim jest i wasz skrypt powinien działać.

Po drugie, pamiętajcie o wywołaniu metody MoveNext w celu przejścia do kolejnego rekordu w zbiorze. Jeśli opuścicie MoveNext, wasz skrypt wyświetli informacje o pierwszym rekordzie, wróci do początku pętli i znowu wyświetli informacje o pierwszym rekordzie. I tak w nieskończoność. Za każdym razem, gdy pracujecie z zestawem rekordów Active Directory, należy wyraźnie powiedzieć skryptowi, aby przeszedł do kolejnego rekordu. Jeśli nie powiecie, nie zrobi tego.

I to by było na tyle, DB. Jak mówiliśmy, nie pomoże ci to za bardzo z problemami z jajecznicą; na szczęście są jednak całe zespoły naukowców i inżynierów pracujące nad rozwiązaniem tych problemów.

Uwaga. Dla pełnej jasności warto wspomnieć, że Skrypciarze sami podjęli się znalezienia rozwiązania. Wstrząsaliśmy bardzo mocno kurą zanim złożyła jaja, mając nadzieję, że gdy to zrobi, będą już wymieszane. (Uwaga redaktora: Nie, tak naprawdę tego nie zrobiliśmy. I wy też nie próbujcie.) Jak to poszło? Ujmijmy to w ten sposób: nie tak dobrze, jak byśmy chcieli. Kura też nie była szczególnie zadowolona.

 Do początku strony Do początku strony

Centrum Skryptóe - Active Directory