Centrum skryptów - Systemy operacyjne

Jak użyć jednocześnie nazw operatorów AND i OR w pojedynczej kwerendzie WMI?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

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 użyć jednocześnie nazw operatorów AND i OR w pojedynczej kwerendzie WMI?

Cześć, Skrypciarze! Przeszukałem chyba całe centrum skryptów, ale nigdzie nie byłem w stanie znaleźć odpowiedzi na frapujące mnie pytanie. Potrzebuję wyszukać wszystkie pliki .DOC na dyskach C i D używając do tego pojedynczej kwerendy. Innymi słowy, potrzebna mi kwerenda w stylu: Where ( Drive = 'C:' or 'D:' ) and ( Extension = 'doc' ); czy da się umieścić zarówno AND jak i OR w pojedynczej kwerendzie?

-- MW

Cześć, MW! Wszyscy na pewno zastanawiacie się, czemu od tak dawna pomijam wątek kariery baseballowej Skrypciarskiego Syna. Czy coś z nią nie tak, lub czy coś z NIM nie tak? Oczywiście, że z NIM, i to niejedno. Najbardziej irytujący jest fakt, że w koszykówkę rozkłada mnie na łopatki. Jest co prawda o głowę ode mnie wyższy, ale to go w żaden sposób nie tłumaczy.

Największy problem ze Skrypciarskim Synem to problem geograficzny, mieszka on przecież w okolicach Seattle, czyli okolicach najbardziej słynących z dobrej passy baseballowej, gdzie treningi odkłada się w nieskończoność, tak samo jak my tu skrypty. Być może dlatego, MW nie mogłeś znaleźć odpowiedzi na swoje pytanie. Tylko że my, w przeciwieństwie do chłopców, po 5. pączku i 5. kawie zabieramy się w końcu do skryptu. Nawet tak trudnego, w którym należy umieścić zarówno OR jak i AND w pojedynczej kwerendzie WMI:

strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set colFiles = objWMIService.ExecQuery _

    ("Select * From CIM_DataFile Where (Drive = 'C:' OR Drive = 'D:') AND Extension = 'doc'")



For Each objFile In colFiles

    Wscript.Echo objFile.Name

Next

Zaczynamy od połączenia się z usługą WMI na komputerze lokalnym, ale to tylko z przyzwyczajenia, skrypt działa bowiem także bez problemów na komputerze zdalnym. Wystarczy tylko przypisać nazwę tego komputera zmiennej strComputer:

strComputer = "atl-fs-001"

To przenosi nas do naszej kwerendy:

Set colFiles = objWMIService.ExecQuery _

    ("Select * From CIM_DataFile Where (Drive = 'C:' OR Drive = 'D:') AND Extension = 'doc'")

WM próbował robić to w następujący sposób:

Set colFiles = objWMIService.ExecQuery _

    ("Select * From CIM_DataFile Where (Drive = 'C:' OR 'D:') AND Extension = 'doc'")

Zakładamy, że nie zadziałało i że dodatkowo dostał następujący komunikat o błędzie:

C:\Scripts\Test.vbs(8,1) (null): 0x80041017

Gdzie leży problem? WMI jest bardzo dokładne jeżeli chodzi o umieszczanie klauzuli Where. Nie wystarczy użyć następującej składni: Drive = 'C:' OR 'D:'. Trzeba to zrobić trochę dokładniej, wskazując która z właściwości może mieć wartość C:and, a która właściwość może mieć wartość D:. Trzeba to zrobić w następujący sposób:

(Drive = 'C:' OR Drive = 'D:')

Jeżeli chcecie dodać jeszcze jakieś dyski, to musicie pamiętać, żeby przed każdą wartością umieścić nazwę właściwości (Drive):

(Drive = 'C:' OR Drive = 'D:' OR Drive = 'E:' or Drive = 'F:')

Etc., etc.

Uwaga: Ile takich klauzul AND oraz OR mozna umieścić w ciągu? Nieskończoność? Nie, jest chyba jakiś limit, bodajże 1 024. Szczerze mówiąc nie ma się jednak co przejmować, jak dużo będzie warunków w klauzuli Where, chociaż z drugiej strony, jeśli będzie ich 1 024, to już można zacząć. Jak się połapać w klauzuli Where o długości kilkuset wierszy kodu?

Prosimy o nie przysyłanie tego pytania do „Cześć, Skrypciarze!”. Nie znamy na nie odpowiedzi dziś i zakładamy, że w najbliższej przyszłości również nie poznamy.

Na pewno zauważyliście również, że klauzulę OR umieściliśmy w nawiasach:

("Select * From CIM_DataFile Where (Drive = 'C:' OR Drive = 'D:') AND Extension = 'doc'")

Czy nawiasy mają jakieś znaczenie? Tak, mają. WMI zawsze zajmuje się zadaniami z nawiasów przed wszystkimi innymi. Rozdzieli sobie więc kwerendę w sposób następujący:

  • Wybierz wszystkie wystąpienia klasy CIM_DataFile.
  • Wybierz podzbiór tych wystąpień; tj. tylko te pliki, których dysk równy jest C: lub D:.
  • Wybierz podzbiór tych wystąpień; tj. tylko te pliki na dysku C lub D, których rozszerzenie (Extension) jest równe doc.

Przypuśćmy teraz, ze mieliliśmy nawiasy w innym miejscu. Ta sama kwerenda, inne nawiasy:

("Select * From CIM_DataFile Where Drive = 'C:' OR (Drive = 'D:' AND Extension = 'doc')")

WMI rozdzieli tę kwerendę w sposób następujący:

  • Wybierz wszystkie wystąpienia klasy CIM_DataFile.
  • Wybierz podzbiór tych wystąpień, tj. tylko te pliki, których litera dysku jest C:. Jaki efekt? Pobierz wszystkie pliki z dysku C, bez względu na ich rozszerzenia.
  • Oprócz wszystkich plików na dysku C pobierz wszystkie pliki, których litera dysku jest równa D:, a rozszerzenie równe doc.

Innymi słowy, przesuwając nawias w ten sposób otrzymamy wszystkie pliki z dysku C plus wszystkie pliki .DOC z dysku D. Jeżeli usuniecie wszystkie nawiasy WMI użyje następującego toku rozumowania podczas przetwarzania kwerendy:

  • NOT
  • AND
  • OR

U nas to się nie sprawdzi, bez nawiasów bowiem nasza kwerenda wyglądałaby w następujący sposób:

("Select * From CIM_DataFile Where Drive = 'C:' OR Drive = 'D:' AND Extension = 'doc'")

Z uwagi na to, że WMI przetwarza operator AND przed operatorem LUB, kwerenda będzie przetworzona tak jak gdyby była napisana w następujący sposób:

("Select * From CIM_DataFile Where Drive = 'C:' OR (Drive = 'D:' AND Extension = 'doc')")

Jak juz zauważyliśmy, taka kwerenda nie przyniesie nam oczekiwanych rezultatów. Jaki więc morał z naszej dzisiejszej historii? Zawsze używaj nawiasów w klauzulach Where, czy to w skryptach, czy nie. Lepiej nie ryzykować.

Co zaś tyczy się reszty skryptu to ustawiamy tu po prostu pętlę For Each, która przechodzi przez całą kolekcję plików, przywołując echo nazwy (Name) każdego napotkanego pliku:

For Each objFile In colFiles

    Wscript.Echo objFile.Name

Next

Chodziło nam właśnie o to – przywołanie echa nazwy każdego pliku .DOC na dysku C i D.

Sukces.

Chociaż na tym polu odniosłem sukces, niedługo czeka mnie bowiem kolejna porażka podczas gry w koszykówkę. Może wymigam się pod pretekstem kolejnego skryptu. Zobaczmy, jakie jest zapytanie na dzień 0321…

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne