Centrum skryptów - Systemy operacyjne

Jak znaleźć w drzewie katalogowym wszystkie pliki zawierające określone słowo lub zwrot?

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 znaleźć w drzewie katalogowym wszystkie pliki zawierające określone słowo lub zwrot?

Cześć Skrypciarze! Pytanie

Cześć Skrypciarze! Jak znaleźć w drzewie katalogowym wszystkie pliki zawierające określony zwrot?

-- PB

Cześć Skrypciarze! Odpowiedź

Cześć, PB. Być może na to nie wygląda, ale mam dzisiaj kiepski humor. Pierwszy raz po kilkutygodniowej przerwie grałem w kosza ze swoim synem i wygrałem. W zasadzie to powinienem mieć z tego powodu dobry humor, ale skomentowaniu mojej wygranej przez Skrypciątko jest wprost przeciwnie. Podobno miałem po prostu szczęście i nie miała ona nic wspólnego z tym, że jestem taki wysportowany i mam świetną taktykę.

Co on może wiedzieć? Trafienie do kosza nie ma nic wspólnego ze szczęściem. Szczęście to jest wtedy, gdy ktoś potrzebuje skryptu, który znajdzie wszystkie pliki zawierające określone słowo i nagle ktoś mu taki skrypt podsuwa pod nos.

Skrypt taki, jak ten poniżej:

On Error Resume Next



Set objConnection = CreateObject("ADODB.Connection")

Set objRecordSet = CreateObject("ADODB.Recordset")



objConnection.Open "Provider=Search.CollatorDSO;Extended Properties='Application=Windows';"



objRecordSet.Open "SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains('Alice') " _

    & "AND System.ItemPathDisplay LIKE 'C:\Scripts\%'", objConnection



objRecordSet.MoveFirst



Do Until objRecordset.EOF

    Wscript.Echo objRecordset.Fields.Item("System.ItemPathDisplay")

    objRecordset.MoveNext

Loop

Zanim posuniemy się odrobinę dalej, powinniśmy zauważyć, że ten skrypt wykorzystuje Windows Desktop Search 3.0 (j.ang.) – całkiem nową, w pełni kompatybilną ze skryptami technologię, która jest wbudowana w system Windows Vista (a ponadto może być pobierana i instalowana na innych wersjach systemu Windows). Wybraliśmy to podejście z dwóch powodów:

  • Jest o wiele prościej uzyskać dostęp do wszystkich folderów znajdujących się w drzewie katalogowym za pomocą Desktop Search niż używając usługi WMI lub obiektu FileSystemObject. Wykonanie tego zadania za pomocą usługi WMI lub obiektu FileSystemObject wymagałoby napisanie pewnej szalonej podprocedury rekurencyjnej, która mogłaby dotrzeć do każdego pojedynczego folderu w drzewie katalogowym. Wbrew powszechnej opinii, Skrypciarze nie lubią robić rzeczy szalonych. (Nie, żebyśmy ich w ogóle nie robili, ale ich nie lubimy.)
  • Program Windows Desktop Search może otworzyć – i przeszukać – wszystkie typy plików, włączając dokumenty programu Word, arkusze kalkulacyjne programu Excel, prezentacje programu PowerPoint, itd. Bez możliwości zastosowania programu Desktop Search bylibyśmy ograniczeni do przeszukiwania jedynie plików tekstowych. (OK, teoretycznie moglibyśmy przeszukać także inne typy dokumentów, ale musielibyśmy uwzględnić kod identyfikujący, otwierający i przeszukujący dokumenty programu Word plus kod identyfikujący, otwierający i przeszukujący arkusze kalkulacyjne programu Excel plus kod identyfikujący, otwierający i przeszukujący... sami wiecie, co idzie dalej.)

Tak czy siak, być może istnieją także inne sposoby wykonania tego zadania, ale stwierdziliśmy, że najprostszym będzie zastosowanie programu Desktop Search. Jeżeli chodzi o Skrypciarzy, najprostszy sposób jest zawsze najlepszym sposobem.

Zatem w jaki dokładnie sposób używamy programu Desktop Search do wykonania tego zadania? No cóż, na początek tworzymy parę obiektów ADO (ActiveX Data Objects); zastosujemy obiekt ADODB.Connection w celu połączenia się z indeksem plików programu Desktop Search, a obiekt ADODB.Recordset wykorzystamy jako magazyn dla wszelkich informacji zwróconych przez naszą kwerendę. Po utworzeniu tych dwóch obiektów używamy metody Open obiektu Connection w celu połączenia się z programem Windows Desktop Search:

objConnection.Open "Provider=Search.CollatorDSO;Extended Properties='Application=Windows';"
Uwaga. Co się dzieje w tym wierszu kodu? Cóż, szczerze mówiąc, sami nie wiemy dokładnie. Ani nas to specjalnie nie obchodzi. Jest tak dlatego, że jest to tekst standardowy: używamy go w niezmienionej postaci za każdym razem, gdy chcemy użyć programu Desktop Search i wszystkich to zadowala.

Kiedy otwieramy miejsce przechowywania danych, dochodzimy do sedna działania każdego skryptu: części, w której dokładnie określamy to, czego szukamy. W tym przypadku, wywołujemy metodę Open obiektu Recordset, przekazując jej dwa parametry: kwerendę SQL zawierającą nasze kryteria wyszukiwania oraz odniesienie do obiektu Connection (objConnection):

objRecordSet.Open "SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains('Alice') " _

    & "AND System.ItemPathDisplay LIKE 'C:\Scripts\%'", objConnection

Jeżeli chodzi o mnie, jedyną częścią tego polecenia, która naprawdę się liczy to sama kwerenda SQL:

"SELECT System.ItemPathDisplay FROM SYSTEMINDEX WHERE Contains('Alice') " & _

    "AND System.ItemPathDisplay LIKE 'C:\Scripts\%'"

Zobaczmy, czy uda nam się dojść do tego, co się tutaj dzieje. Dla potrzeb naszego dzisiejszego skryptu, jedyną rzeczą, która nas dzisiaj obchodzi jest ścieżka dostępu do każdego pliku zawierającego słowo Alice. (Tak przy okazji, wielkość znaków nie jest tutaj istotna; wyszukiwanie zlokalizuje Alice, alice oraz ALICE, jak również wszelkie inne odmiany tego słowa.) Podczas pracy z programem Desktop Search należy określić każdą wartość właściwości, którą chcemy uzyskać. Ponieważ właściwość System.ItemPathDisplay zawiera ścieżkę pliku, zaczynamy naszą kwerendę od:

SELECT System.ItemPathDisplay

Następna część kwerendy (FROM SYSTEMINDEX) to także tekst standardowy; jedynie program Desktop Search ma „tabelę” (SYSTEMINDEX) której może dotyczyć kwerenda. To nas sprowadza do zdania WHERE, zawierającego kryteria, które muszą zostać spełnione, aby można było pobrać informacje o pliku:

  • Plik musi zawierać słowo Alice. Do tego służy składnia Contains('Alice'): dzięki niej skrypt odczytuje zawartość pliku i sprawdza, czy słowo Alice może zostać zlokalizowane w tej zawartości. (OK, technicznie rzecz biorąc, program Desktop Search dokonał już odczytu pliku; nie ma potrzeby wykonywania tej czynności przez skrypt. Wiecie, co mam na myśli.)
  • Plik musi się znajdować gdzieś w drzewie katalogowym C:\Scripts. Składnia System.ItemPathDisplay LIKE 'C:\Scripts\%' mówi o tym, że ścieżka pliku (System.ItemPathDisplay) musi zaczynać się od C:\Scripts\. Operator LIKE umożliwia nam zastosowanie w naszej kwerendzie symbolu wieloznacznego; tak się składa, że ten symbol to znak procentu (%), który spełnia takie samo zadanie, jak gwiazdka w poleceniu dir (np. dir C:\Scripts\Test.*). innymi słowy, znak procentu powoduje, że to zadanie możemy odczytać następująco: „Pokaż mi każdy plik, w którym ścieżka rozpoczyna się od C:\Scripts\, niezależnie od tego, co (jeżeli cokolwiek) znajduje się za C:\Scripts\.” To z kolei umożliwia nam zlokalizowanie plików znajdujących się w folderze C:\Scripts (np. C:\Scripts\Test.txt), jak również plików znajdujących się w podfolderze folderu C:\Scripts (np. C:\Scripts\Subfolder1\Test.txt).

To o wiele prostszy sposób, niż napisanie podprodcedury rekurencyjnej wykonującej to samo, niby banalne, zadanie dostępu do wszystkich plików znajdujących się w drzewie katalogowym.

Po wykonaniu kwerendy, stosujemy metodę MoveFirst w celu przejścia do następnego rekordu w pobieranym zbiorze rekordów. (Nie mamy 100% pewności, że to jest konieczne, ale zawsze lepiej się zabezpieczyć, nieprawdaż?) Następnie uruchamiamy pętlę Do Until która będzie działać, dopóki nie dojdzie do końca zbioru rekordów; czyli dopóki właściwość EOF (end-of-file) zbioru rekordów nie uzyska wartości True:

Do Until objRecordset.EOF

Wewnątrz tej pętli nie mamy wiele do zrobienia; po prostu wywołujemy echo właściwości System.ItemPathDisplay, a następnie wywołujemy metodę MoveNext, aby móc kontynuować i powtarzamy cały proces dla następnego rekordu w zbiorze rekordów:

Wscript.Echo objRecordset.Fields.Item("System.ItemPathDisplay")

objRecordset.MoveNext

Po zakończeniu wszystkich czynności powinniśmy otrzymać podobny do poniższego raport:

C:\Scripts\Scores.xls

C:\Scripts\Alice2.txt

C:\Scripts\Decoded.txt

C:\Scripts\Decrypt.txt

C:\Scripts\New Folder\New Folder\New Text Document.txt

Zauważmy tutaj dwie rzeczy. Po pierwsze, pierwszy plik na liście to arkusz kalkulacyjny programu Excel; jak zauważyliśmy wcześniej, program Desktop Search ma możliwość wykonywania wyszukiwania w dokumentach pakietu Microsoft Office. (Między innymi, program Desktop Search może także wykonywać wyszukiwanie w plikach .PDF.) Zauważmy także, że ostatni plik na liście znajduje się w pod-podfolderze folderu C:\Scripts, co oznacza, że my naprawdę przeszukujemy całe drzewo katalogowe C:\Scripts.

I to nam powinno wystarczyć, PB. Jak już mówiłem, być może są jeszcze inne sposoby wykonania tego zadania, jednak program Desktop Search sprawia, że proces jest bardzo szybki i bardzo prosty. Z uwagi na fakt, iż program Desktop Search ma mnóstwo innych możliwości, warto przyjrzeć mu się bliżej. (Więcej informacji na jego temat można znaleźć w artykule Cluster Continuous Replication (j. ang.))

Po dłuższym namyśle stwierdzam, że mój kosz ma wiele wspólnego ze szczęściem. W zasadzie to nawet więcej. To samo szczęście. W sumie to nawet podczas rzucania piłki do kosza nie miałem nawet nadziei na to, że trafię, chciałem tylko, żeby się odbiła, abym mógł spróbować jeszcze raz.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne