How Can I List the Files in a Folder and All Its Subfolders?

How Can I List the Files in a Folder and All Its Subfolders?

  • Comments 9
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I list all of the files in a folder, as well as all the files in any subfolders of that folder?

-- MA

SpacerHey, Scripting Guy! AnswerScript Center

Hey, MA. This is a question we get asked quite a bit, and one which have avoided answering up till now. That’s because there is no nice, simple answer to this one: a script that can carry out this task is bound to be a little bit confusing, and isn’t going to lend itself to the easy-to-explain approach we like to take with this column. On the other hand, the customer is always right: if you guys want a script that can list all the files in a folder, as well as all the files in any subfolders of that folder, well, who are we to argue?

Before we begin there are two issues we have to grapple with here. First, we need to pick a scripting technology. WMI, the FileSystemObject, and the Shell object are all capable of listing the files in a folder, as well as listing the subfolders in a folder. However, none of these technologies have a mechanism to automatically list the files in those subfolders (not to mention any sub-subfolders that might be found there). Any of these technologies will do the trick, but none will do it very easily.

We opted to go with WMI. The resulting script is perhaps a little more complicated than a similar script using the FileSystemObject or the Shell object, but a WMI script that can retrieve this kind of information on the local computer can just as easily retrieve this kind of information from a remote computer. That’s not the case with either the FileSystemObject or the Shell object. We voted for the flexibility of WMI.

Second, we noted that none of the scripting technologies has a built-in way to iterate through a folder, list the file names, and then automatically iterate through any and all subfolders and list the files found there. Because of that, we need to use a recursive function to perform this task. Explaining recursion is a bit beyond what we can do in this column; for a brief explanation, check out the Microsoft Windows 2000 Scripting Guide. Suffice to say that we’re creating a function that can call itself as many times as needed. In other words, if we have a function that accesses a folder and lists all its files, that function can call itself to access a subfolder and list all the files found there. And then call itself again to access a sub-subfolder. It’s hard to visualize, but it works.

There’s another complication, too, but we’ll deal with that in a minute. For now, let’s take a look at a script that lists a folder and any and all of its subfolders (although this first sample doesn’t list any files found in those folders):

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

What we’re doing here is using an AssociatorsOf query to get a list of all the subfolders of the folder C:\Scripts. Basically our query says this: Get me a list of all the items associated with the directory C:\Scripts, provided those items are subdirectories (Where AssocClass = Win32_Subdirectory).

This gets us a list of all the top-level subfolders: for example, C:\Scripts\Folder1 and C:\Scripts\Folder2. What it doesn’t get us are any second-level folders; this query does not return a folder like C:\Scripts\Folder1\SubfolderA. To get at these sub-subfolders (subfolders of a subfolder) we need to use a recursive query. That’s what the subroutine GetSubFolders does. We pass it - one-by-one - the name of each subfolder we find (like C:\Scripts\Folder1 and C:\Scripts\Folder2) and let it query each of those subfolders for any sub-subfolders. If there are any sub-subfolders, the function will automatically call itself and look for any sub-sub-subfolders.

Confused? Don’t feel bad; you aren’t the only one. But don’t worry about it; just leave the code as-is and give it a try. To search a different folder (that is, one other than C:\Scripts) simply change the value of the variable containing the folder you want to search. For example, if you want to search C:\Windows, then use this line of code:

strFolderName = "c:\windows"

Now, what about the files found in all these folders? Well, this is where things really get complicated. That’s because we need to make an additional query: we use one query to get the names of all the subfolders, and then a second query to get the collection of files found in each folder. That second query happens to look a lot like this:

Set colFiles = objWMIService.ExecQuery _
    ("Select * from CIM_DataFile where Path = '" & strPath & "'")

That’s not too bad, except for this: in a query such as this, we must “escape” (double-up) any \’s found in the file paths. We can’t use C:\Scripts\Folder1\ in our query; we have to use C:\\Scripts\\Folder1\\ instead. You’ll see code in the script that replaces each \ with \\; that’s just something we need to do when referencing a file path in a query like this. A good chunk of the script is doing nothing more than converting the folder path names so they can be used in the query.

So much for all the caveats. Here’s the script everyone has been dying to get their hands on:

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

We told you it was complicated. But it works. This script will bind to the C:\Scripts folder and echo the names of all the files found there; the script will then get a list of all the subfolders found in C:\Scripts. From there we loop through the collection of subfolders, calling the recursive function GetSubFolders for each one. That function will list all the files found in the subfolder, then check to see if the subfolder has any sub-subfolders. If it does, the recursive function will be called again, and the process will continue to repeat itself until we reach the end of the line: until we’ve listed every file found in C:\Scripts and in all its subfolders.

Tomorrow we should go back to an easy one. Anybody out there want to know how to get the name of the local computer using a script?


Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • <p>&quot;...and one which have avoided answering up till now.&quot;</p> <p>Me thinks not ;o)</p> <p>See FileSystemObject version here:</p> <p><a rel="nofollow" target="_new" href="http://blogs.technet.com/heyscriptingguy/archive/2004/10/20/how-can-i-get-a-list-of-all-the-files-in-a-folder-and-its-subfolders.aspx">http://blogs.technet.com/heyscriptingguy/archive/2004/10/20/how-can-i-get-a-list-of-all-the-files-in-a-folder-and-its-subfolders.aspx</a></p> <p>Regards,</p> <p>Daz.</p>

  • <p>This program crashes when it reaches a folder that looks like </p> <p>C:\Program Files\Adobe\Reader 9.0\Setup Files\{AC76BA86-7AD7-1033-7B44-A93xxxxxxxxx}</p> <p>Can anyone provide a solution please</p>

  • <p>I get a error with that script if I have a html file with a attached folder. This kind of folder which gets auto created if you save a Visio as Web page and the folder gets also deleted auto if you remove the html file. Was trying to fix that, but without success....</p> <p>Error comes up with 0x80041017 on line 6 from the end.</p>

  • <p>If you just need this as a listing you could use it via batch script.</p> <p>1. Open Command Prompt (cmd)</p> <p>2. go to the folder </p> <p> &nbsp; (example C:\Files you would type </p> <p>C:</p> <p>CD \</p> <p>CD Files</p> <p>3. Type (without quotation marks) &quot;echo tree /F &gt; listing.txt&quot;</p>

  • <p>If all the files are the same format, &nbsp;click on the base folder you want to list, and type the format into the search bar.</p>

  • <p>This is great and almost what I&#39;m looking for but ideally I want to create an XML file that has all of the file names in it rather than having them pop up on the screen... any idea on whether this is possible please and how to acheive it? Thanks</p>

  • <p>Am I the only one finding this part of code funny (and useless) ?</p> <p>--</p> <p>For Each objFolder in colSubfolders</p> <p> &nbsp; &nbsp;GetSubFolders strFolderName</p> <p>Next</p> <p>--</p>

  • <p>And while I am shamelessly stealing code, please update with code below to avoid problems with directories using quote(s) in their name (stolen from David Brown on Google mailing list):</p> <p>--</p> <p>Rather than using the single-quote (&#39;) as a delimiter, you can use the double-quote</p> <p>(&quot;) if you escape it. &nbsp;In VBS you escape a character by doubling it, so &quot;&quot;</p> <p>. &nbsp;For some reason, this seems to work better in this situation.</p> <p>Using the following revision, I was able to get folders with &#39; or } in them,</p> <p>but I had to escape the backslashes ( \\ )</p> <p>strFolderName = &quot;c:\\quote_test\\b{o&#39;t}h&quot;</p> <p>&quot;Associators of {Win32_Directory.Name=&quot;&quot;&quot; &amp; strFolderName &amp; &quot;&quot;&quot;} &quot; _</p> <p> &nbsp; &nbsp; &nbsp; &nbsp;&amp; &quot;Where AssocClass = Win32_Subdirectory &quot; _</p> <p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; &quot;ResultRole = PartComponent&quot;</p> <p>--</p>

  • <br/>This script does not seem to be able to process UNC paths.<br/><br/>Anyone have any ideas?