Centrum Skryptów - Systemy Operacyjne

Jak utworzyć listę wszystkich plików w folderze i wszystkich podfolderów?

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 utworzyć listę wszystkich plików w folderze i wszystkich podfolderów?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Jak utworzyć listę wszystkich plików w folderze i wszystkich plików znajdujących się w jego podfolderach?

-- MA

Cześć Skrypciarze! Odpowiedź

Cześć, MA. To pytanie pojawia się dosyć często, ale jak dotąd unikaliśmy odpowiadania na nie. A to dlatego, że nie ma tu prostego i zgrabnego rozwiązania – skrypt mogący wykonać to zadanie będzie na pewno trochę zakręcony, co odbije się też na naszej odpowiedzi. Z drugiej jednak strony, klient ma zawsze rację – skoro zależy Wam na skrypcie mogącym utworzyć listę plików w folderze i jego podfolderach, to proszę bardzo.

Zanim zaczniemy, trzeba jeszcze poruszyć dwie kwestie. Po pierwsze, musimy wybrać technologię skryptów. Listę plików w folderze i listę podfolderów można utworzyć za pomocą WMI, FileSystemObject lub obiektu Shell. Jednak żadna z tych technologii nie pozwala na automatyczne tworzenie listy plików znajdujących się w podfolderach, czy też podfolderach podfolderów. Możemy wybrać dowolną z nich, bo z każdą będzie tak samo trudno.

Zdecydowaliśmy się wybrać WMI. Powstały w ten sposób skrypt jest może trochę bardziej złożony od analogicznego, używającego technologii FileSystemObject lub obiektu Shell, ale może z równą łatwością (trudnością?) pobierać informacje z lokalnego, co ze zdalnego komputera. Inaczej jest w przypadku FileSystemObject i Shell. Zdecydowaliśmy, że elastyczność WMI jest ważniejsza.

Po drugie, zauważyliśmy, że żadna z technologii skryptów nie ma wbudowanej funkcji umożliwiającej przejście przez wszystkie podfoldery i utworzenie listy znajdujących się tam plików. Dlatego musimy użyć tzw. funkcji rekursywnej. Wyjaśnienie rekursji wybiega trochę poza zakres niniejszego artykułu; można je znaleźć w przewodniku Microsoft Windows 2000 Scripting Guide (j.ang.). Na razie wystarczy, jeśli powiemy, że chodzi o funkcję, która może uruchomić się tyle razy, ile będzie wymagane. Innymi słowy, nasza funkcja otworzy folder i utworzy listę znalezionych w nim plików, a następnie uruchomi się ponownie, otworzy podfolder tego folderu i utworzy listę plików, które się w nim znajdują. A następnie uruchomi się ponownie, otwierając pod-podfolder itd. Nie jest to może szczególnie zgrabne, ale działa.

Mamy jeszcze jedno utrudnienie, którym zajmiemy się za chwilę. Na razie rzućmy okiem na skrypt tworzący listę folderów i znajdujących się w nich podfolderów (w pierwszej wersji nie tworzymy jeszcze list plików):

strComputer = "."

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



strFolderName = "c:\scripts"



Set colSubfolders = objWMIService.ExecQuery _

    ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _

        & "Where AssocClass = Win32_Subdirectory " _

            & "ResultRole = PartComponent")



For Each objFolder in colSubfolders

    GetSubFolders strFolderName

Next



Sub GetSubFolders(strFolderName)

    Set colSubfolders2 = objWMIService.ExecQuery _

        ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _

            & "Where AssocClass = Win32_Subdirectory " _

                & "ResultRole = PartComponent")



    For Each objFolder2 in colSubfolders2

        strFolderName = objFolder2.Name

        Wscript.Echo objFolder2.Name

        GetSubFolders strFolderName

    Next

End Sub

Używamy tu kwerendy AssociatorsOf w celu uzyskania listy wszystkich podfolderów folderu C:\Scripts. Znaczenie naszej kwerendy jest właściwie takie: Pobierz listę wszystkich elementów skojarzonych z katalogiem C:\Scripts, będących podkatalogami (Where AssocClass = Win32_Subdirectory).

Uzyskujemy w ten sposób listę wszystkich podfolderów pierwszego rzędu, np. C:\Scripts\Folder1 i C:\Scripts\Folder2. Nie uzyskujemy natomiast podfolderów drugiego rzędu – nie otrzymamy takich folderów, jak C:\Scripts\Folder1\SubfolderA. Do tego potrzebna jest kwerenda rekursywna. Tym właśnie zajmuje się podprogram GetSubFolders. Przekazujemy mu – jedną za drugą – nazwy poszczególnych znalezionych podfolderów (np. C:\Scripts\Folder1 i C:\Scripts\Folder2), w których następnie przeprowadzona zostaje kwerenda wyszukująca pod-podfoldery. W razie ich znalezienia funkcja automatycznie uruchomi się ponownie i wyszuka pod-pod-podfoldery.

Zagubieni? Nie martwcie się, nie Wy jedni. Nie ma się co przejmować, wystarczy pozostawić kod bez zmian i go uruchomić. Aby wyszukać w folderze innym niż C:\Scripts, wystarczy zmienić wartość zmiennej zawierającej jego nazwę. Na przykład w celu przeszukania folderu C:\Windows należy użyć takiego wiersza kodu:

strFolderName = "c:\windows"

Pozostaje jeszcze kwestia plików znajdujących się w tych wszystkich folderach. No cóż, teraz sprawy naprawdę zaczynają się komplikować. Potrzebujemy bowiem dodatkowej kwerendy, która będzie pobierać kolekcje plików wyszukiwanych w poszczególnych folderach. Tak się składa, że wygląda ona tak:

Set colFiles = objWMIService.ExecQuery _

    ("Select * from CIM_DataFile where Path = '" & strPath & "'")

Nie tak źle, pomijając jedno – w takiej kwerendzie musimy oznaczyć, czyli zdublować, każdy znak \ w ścieżkach plików. Nie możemy użyć w kwerendzie ścieżki C:\Scripts\Folder1\; musimy ją zapisać jako C:\\Scripts\\Folder1\\. W skrypcie można znaleźć kod zastępujący znak \ ciągiem \\. Spora część skryptu służy tylko do takiego przekształcania ścieżek, by nadawały się do zastosowania w kwerendzie.

To tyle jeśli chodzi o kwestie problematyczne. Oto skrypt, na który wszyscy czekali:

strComputer = "."

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



strFolderName = "c:\scripts"



Set colSubfolders = objWMIService.ExecQuery _

    ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _

        & "Where AssocClass = Win32_Subdirectory " _

            & "ResultRole = PartComponent")



Wscript.Echo strFolderName



arrFolderPath = Split(strFolderName, "\")

strNewPath = ""

For i = 1 to Ubound(arrFolderPath)

    strNewPath = strNewPath & "\\" & arrFolderPath(i)

Next

strPath = strNewPath & "\\"

 

Set colFiles = objWMIService.ExecQuery _

    ("Select * from CIM_DataFile where Path = '" & strPath & "'")



For Each objFile in colFiles

    Wscript.Echo objFile.Name 

Next



For Each objFolder in colSubfolders

    GetSubFolders strFolderName

Next



Sub GetSubFolders(strFolderName)

    Set colSubfolders2 = objWMIService.ExecQuery _

        ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _

            & "Where AssocClass = Win32_Subdirectory " _

                & "ResultRole = PartComponent")



    For Each objFolder2 in colSubfolders2

        strFolderName = objFolder2.Name

        Wscript.Echo

        Wscript.Echo objFolder2.Name

        arrFolderPath = Split(strFolderName, "\")

        strNewPath = ""

        For i = 1 to Ubound(arrFolderPath)

            strNewPath = strNewPath & "\\" & arrFolderPath(i)

        Next

        strPath = strNewPath & "\\"

 

        Set colFiles = objWMIService.ExecQuery _

            ("Select * from CIM_DataFile where Path = '" & strPath & "'")



        For Each objFile in colFiles

            Wscript.Echo objFile.Name 

        Next



        GetSubFolders strFolderName

    Next

End Sub

Mówiliśmy, że będzie trudno. Ale działa. Skrypt połączy się z folderem C:\Scripts i wyświetli listę znajdujących się tam plików, a następnie pobierze listę znajdujących się w nim podfolderów. Następnie skrypt przechodzi przez kolekcję podfolderów, wywołując dla każdego z nich rekursywną funkcję GetSubFolders. Funkcja ta tworzy listę plików znajdujących się w danym podfolderze, a następnie sprawdza, czy są w nim pod-podfoldery. Jeśli tak, ponownie zostanie wywołana funkcja rekursywna, a proces będzie powtarzany, dopóki nie dojdziemy do końca i nie będziemy mieć listy wszystkich plików znajdujących się w folderze C:\Scripts i wszystkich jego podfolderów.

Jutro zajmiemy się czymś prostym. Na przykład: jak uzyskać nazwę komputera lokalnego za pomocą skryptu?

 Do początku strony Do początku strony

Centrum Skryptów - Systemy Operacyjne