List Files in Folders and Subfolders with PowerShell

Summary: Use Windows PowerShell to list files in folders and subfolders.

Hey, Scripting Guy! Question Hey, Scripting Guy! I am an old VBScript guy. I love using VBScript, and I have done so for nearly 15 years. One reason I love VBScript so much is that, to me, it is easy to use. It is also very powerful. But after attending TechEd the last several years, it appears that Microsoft is moving away from VBScript, and is embracing Windows PowerShell.

So, I am trying to learn Windows PowerShell. What I am doing is when I need to make a change to an existing VBScript script, I  attempt to use Windows PowerShell to do the same task. I am having a bit of trouble listing files in folders and in subfolders. Can you give me a push in the right direction?


Hey, Scripting Guy! Answer Hello TJ,

Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sipping a cup of English Breakfast tea. I added a combination spoonful of spearmint leaves, peppermint leaves, licorice root, rose hips, hibiscus, and a cinnamon stick to my pot while I steeped it for four minutes. The tea is very refreshing. Speaking of refreshing, I believe you will find the way that Windows PowerShell handles files and folders a welcome change from the work you had to do in VBScript.

First let me say that I do not hate VBScript. I wrote three books about VBScript, and I had a lot of fun teaching VBScript classes all over the world when I was in MCS. I am not the type of person who wants to say that you should immediately change over VBScript to Windows PowerShell. The point of scripting—regardless of the language—is for automation. Scripting is a tool, a means to a destination, not the destination itself. Therefore, TJ, I believe that you are taking a logical approach to learning Windows PowerShell and preparing for the future of Windows automation.

But, nearly 10 years ago, we posted the following Hey, Scripting Guy! Blog: How Can I Get a List of All the Files in a Folder and Its Subfolders? The script, written in VBScript, was 22 lines long. It was a lot of work to understand, and for someone not really familiar with VBScript, it would be quite confusing. Here is the code—just for fun.

VBScript list files in folders and subfolders

Set objFSO = CreateObject("Scripting.FileSystemObject")

objStartFolder = "C:\Scripts"


Set objFolder = objFSO.GetFolder(objStartFolder)

Wscript.Echo objFolder.Path

Set colFiles = objFolder.Files

For Each objFile in colFiles

    Wscript.Echo objFile.Name




ShowSubfolders objFSO.GetFolder(objStartFolder)


Sub ShowSubFolders(Folder)

    For Each Subfolder in Folder.SubFolders

        Wscript.Echo Subfolder.Path

        Set objFolder = objFSO.GetFolder(Subfolder.Path)

        Set colFiles = objFolder.Files

        For Each objFile in colFiles

            Wscript.Echo objFile.Name



        ShowSubFolders Subfolder


End Sub

There are at least three issues with this script.

One thing to keep in mind is that if you double-click this VBScript script, you potentially will receive thousands of popup message boxes like the one shown here:

Image of message box

Another issue is that whether I click OK, or I click the red “X” in the upper-right corner, the onslaught of popup dialog boxes keeps coming. The only way to retrieve control of the situation (other than rebooting my computer) is to open Task Manager, find the Windows-based script host process, and kill it. This is illustrated in the following image:

Image of menu

The third issue is a bit different. It involves a bit of usability because to change the destination of the script, I must manually edit the script. This involves opening the script in Notepad (the only editor we ship for VBScript), and changing the value of ObjStartFolder.

Now, each of these issues is solvable in that I can check to ensure the script is running in a command prompt via Cscript, and I can add command line input variables to the script. But both of these solutions are going to involve several lines of additional code.

Listing files in folders and subfolders with PowerShell

When it comes to working with files and folders and recursing through a nested directory structure, it is almost an unfair competition between Windows PowerShell and VBScript. It is almost like the Windows PowerShell team deliberately made it easy to work with files and folders.

For example, suppose I have a series of nested folders in my music folder, such as the one shown in the following image. Each folder is a music group, each subfolder is an album, and inside each album are the individual music tracks.

Image of menu

Listing a specific folder

To work with a specific folder, I use the Get-ChildItem cmdlet. This cmdlet has been around since Windows PowerShell 1.0, but in more recent versions of Windows PowerShell, it has gained a couple of additional useful switches. First, just list a specific folder:

Get-ChildItem -Path E:\music

This command lists all files and folders that are at the E:\music level. This command does not recurse through the entire structure. The command and a sample output are shown in the following image:

Image of command output

If I want to only see the folders at this level, I use the –Directory switch.

Note  The –Directory, -File, -Attributes, -Hidden, and –System switches were added to Get-ChildItem cmdlet in Windows PowerShell 3.0. These switches are available via the FileSystem provider. For more information, see Use PowerShell to Find Dynamic Parameters.

This would be the command to see only the directories at the E:\Music level:

Get-ChildItem -Path E:\music –Directory

To see only the files at this level, I change it to use the –File switch:

Get-ChildItem -Path E:\music –File

Use the –Recurse switch

To burrow down into a nested folder structure, I need to use the –Recurse switch. The difference is readily apparent. For example, the following command displays the folders in a specific folder:

Get-ChildItem -Path E:\music\Santana

The output from the command is shown here:

Image of command output

When I use the –Recurse switch, I can see the folders in addition to the files inside each of the folders. The command is shown here:

Get-ChildItem -Path E:\music\Santana –Recurse

In the following image, I see that at first the output is the same—it lists the folders. Then it takes each folder in turn, and displays the files from that folder. This continues until all the files in all the nested folders are displayed.

Image of command output

If I use the –File parameter, I do not get the initial folder list:

Get-ChildItem -Path E:\music\Santana -Recurse –File

The command and output from the command are shown here:

Image of command output

Easy sorting

One of the really cool things that Windows PowerShell does is makes it easy to sort information. There is even a cmdlet named Sort-Object. For example, if I want to see which songs are the longest, I would use this command:

Get-ChildItem -Path E:\music\Santana -Recurse -File | sort length –Descending

The command and output from the command are shown here:

Image of command output

TJ, that is all there is to using Windows PowerShell to list files in folders and subfolders. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (17)

  1. Equicorplegal says:

    Your">matter is very nice and work to cmd

  2. David says:

    So when I -recurse and want to act on the list of files returned by gci, how do I retrieve the directory of the file being acted on? All I can seem to get to is the file name, and not the path it is at.

  3. jv says:

    @David. Have you tried “DirectoryName” – that would seem to be the way to get the directory part of the filename.


    [io.fileinfo]’x’ | gm

  4. Nanda G. says:

    Too good article, very useful especially with windows 2008.

  5. OlavRG says:

    In case you want a more visually accessible overview of files and folders, use:
    tree /F

    Note: I just started using PowerShell today, for the very purpose of generating a quick overview of my file structure in text format, and stumbled upon this question. Just thought I’d post this as an alternative to get-childitem. I found this approach on

  6. sam says:

    Have an application that is generating a logs in many subfolders and subfolders. for EX: c:rootlogging1componenet1, c:rootlogging2 … like this.

    these logs are kept for 30 days, most of these files are txt .log files. I know I cannot delete the folders because they are locked in the process. but I need to delete files from every folder underneath c:root keeping only two days of data. anything older
    than two days should be deleted .

    Could you help/guide us how to write a script like that.

    Thank you

  7. Steve says:

    Thanks a lot this is great!

  8. shubham says:

    you first program(without power shell) wont work fully if you give objStartFolder = "C:"’
    it will show permission denied and will not give the list of all the files and folder
    how you deal with this

  9. Raghavendra Maiya says:

    Script for displaying extreme files and folders in a folder is very useful. Thanks for posting this buddy.

  10. srikanth says:

    Currently we manually check our server on daily basis to see if any files have arrived from any university.There approximately 15 university folders all starting with univ on server.
    each has import ,export and other folders under them.
    need powershell script to check these import folders on daily basis and send an email to *****@**.com showing which universities have files in their import folders

  11. CJay says:

    What if you do not want the files? Just the folder. I want folders and subfolder so -recurse is needed but I dont care to see all of the files inside of each folder.

  12. Tim A says:

    This is helpful.

    What would be even more helpful in my scenario is:
    being able to list all files and ‘the path’ to each file. Similar to what David posted on 4/5/2014.

    I did a FL and found only these properties (I assume they are properties 🙂 )
    Name : _History.txt
    Length : 1711
    CreationTime : 4/18/2008 1:04:31 PM
    LastWriteTime : 6/14/2007 4:01:30 PM
    LastAccessTime : 3/24/2015 6:30:43 PM
    VersionInfo : File: D:History.txt
    Debug: False
    Patched: False
    PreRelease: False
    PrivateBuild: False
    SpecialBuild: False

    it looks like if you do a command like this:
    gci -file | ft -a versioninfo, name

    you should get the info….. but for some reason the versioninfo ends up with ……..

    File: Z:SpearSheet1.xlsx…
    File: Z:SpearSheet2.xlsx…
    File: Z:SpearSheet3.xlsx…

    and then the ‘name’ doesn’t show up

    I realized that VersionInfo actually consists of all of this:
    VersionInfo : File: Z:SpearSheet1.xlsx
    Debug: False
    Patched: False
    PreRelease: False
    PrivateBuild: False
    SpecialBuild: False

    so if you do the same command with "-wrap"
    gci -file | ft -a versioninfo, name -wrap

    you still loose the name (unless I just missed it).

    So I did it like this:
    gci -file | ft -a name, versioninfo -wrap

    and got more of what i’m looking for, but with all the extra VersionInfo.

    Then I figured, since all I needed was the first line of VersionInfo. I removed the -wrap:
    gci -file | ft -a name, versioninfo

    downside here is you get this prefacing your path:

    Then another downside is, you get the filename included in the path

    Then you have the ‘…’ after each filename

    so, if you just run this (exporting to a file):
    gci -file | ft -a versioninfo > C:results.txt

    you can use find/replace to get rid of the "File: "
    and another replace for the "…"

  13. VirtualGathis says:

    It’s too bad the script guy couldn’t write this for all default versions of powershell. Powershell 3.0 is not installed by default so -directory is worthless to me. Windows server came with PS 2.0 I am not authorized to install software to the server so
    updating the powershell is not an option. So that said how do you do all these wonderful things with PS 2?

  14. Arnumb says:

    Hey Scripting Guy!
    Excellent article. Landed on this page while I was stuck on a similar issue, and this page helped me resolve it like a char. Thanks.

    PS: Awesome music collection you got there!


  15. Randman says:

    Thanks for the tips. It got me down the correct path. I was trying to pull back just folder names (including all nested dirs) and came up with a two liner that will allow me to compare output against another location.

    $dir1 = "ServerName1C$Program Files"
    gci -Recurse -Attributes D -Name -Path $dir1 | Out-File ServerName1_Dir_Structure.txt -Force
    $dir2 = "ServerName2C$Program Files"
    gci -Recurse -Attributes D -Name -Path $dir2 | Out-File ServerName2_Dir_Structure.txt -Force

    I can then use other compare-object or a 3rd party diff tool to present the diff to release management.

Skip to main content