Create file list in every subfolder using PowerShell

3.9k views Asked by At

I'm very new to PowerShell and have basically zero knowledge about PowerShell scripting, which is why I need some help.

I have folder structure with subfolders (as shown below) for which I want to generate a filelist.txt in every 1st level subfolder using Get-ChildItem -Recurse.

Main Folder  
├───Sub 1
│   │   file.ext
│   └───Sub A
│           file.ext   
└───Sub 2 
|   |   file.ext
|   └───Sub B
└─── etc.

So far, I experimented with some code I found online but either I'm getting errors or absolutely nothing happens. This is the closest thing to what I want, as it creates filelist.txt files in the correct directories, but unfortunately those files are empty. In addition, a filelist.txt is created in the main folder which I don't want.

Get-ChildItem -Recurse -Directory | 
    ForEach-Object {
        New-Item -ItemType file -Path "$($_.FullName)" -Name "filelist.txt"
        Get-ChildItem $_ -Recurse > filelist.txt
    } 

Any help or suggestions are very appreciated!

4

There are 4 answers

2
Santiago Squarzon On BEST ANSWER

If you're looking for the immediate sub-folders of Main Folder you shouldn't use -Recurse on your first call to Get-ChildItem -Directory as that would give you all sub-folders recursively as zett42 pointed out in his helpful comment.

Regarding your export line:

Get-ChildItem $_ -Recurse > filelist.txt

It would place the filelist.txt file on your current location not on the subfolders, it would also replace the file per loop iteration.

The code would look like this if I understood correctly what you were looking for:

Get-ChildItem 'path\to\Main Folder' -Directory | ForEach-Object {
    $destination = Join-Path $_.FullName -ChildPath filelist.txt
    Get-ChildItem -LiteralPath $_.FullName -Recurse |
        Set-Content $destination
}

Worth noting that this would only export the absolute paths of the files and folders under each sub-folder of Main Folder, however it might be worth changing the export type to CSV to have the properties of each object as you see them on your console:

    $destination = Join-Path $_.FullName -ChildPath filelist.csv
    Get-ChildItem -LiteralPath $_.FullName -Recurse |
        Export-Csv $destination -NoTypeInformation
0
RetiredGeek On

I think what you want is:

Get-ChildItem -Path $BaseFolder -Depth 1

You can mess with the -Depth argument if you need another level.

0
another victim of the mouse On

Here's what I did.

##variables
$startingLocation = Get-Location
$subs = Get-ChildItem -Recurse -Depth 1 -Directory
$startingCheck = ($startingLocation).Path + "\filelist.txt"


##create starting list in original directory
##check if it exists already and write to it
if ( Test-Path -Path $startingCheck) {
    Get-ChildItem -Recurse >> filelist.txt
}

else {
    Write-Warning "File doesn't exist... creating file."
    New-Item -ItemType File -Path $startingLocation -Name "filelist.txt"
    Write-Warning "File created."
    Get-ChildItem -Recurse >> filelist.txt
    Write-Warning "File created and now writing GCI to log."
}

##loop
foreach ($s in $subs) {

    ##go to the location
    Set-Location -Path $s.FullName -Verbose

    ##test if output file exists in current directory of loop
    $testPwd = Get-Location  -Verbose
    $currentPath = ($testPwd).Path + "\filelist.txt"
   
    ## if the file already exists - write GCI to it
    if (Test-Path -Path $currentPath) { 
        Get-ChildItem -Recurse -Depth 1 >> filelist.txt
        Write-Warning "File exists... writing GCI to log."
    }

    ## otherwise if there is no file, make one and write GCI to it
    else {
        Write-Warning "File doesn't exist... creating file."
        New-Item -ItemType File -Path $testPwd -Name "filelist.txt"
        Write-Warning "File created."
        Get-ChildItem -Recurse -Depth 1 >> filelist.txt
        Write-Warning "File created and now writing GCI to log."
    }

    ##exit the loop
}
#go back to original location
Set-Location $startingLocation

Before:

Folder PATH listing for volume Windows
Volume serial number is A4DB-B980
C:.
│   test.ps1
│
├───Folder1
│   │   doc1.txt
│   │   doc2.txt
│   │
│   ├───FolderA
│   └───FolderB
│       └───FolderB1
│               doc1b.txt
│               doc2b.txt
│
├───Folder2
│   ├───FolderA
│   └───FolderB
└───Folder3

Result:

Folder PATH listing for volume Windows
Volume serial number is A4DB-B980
C:.
│   filelist.txt
│   test.ps1
│
├───Folder1
│   │   doc1.txt
│   │   doc2.txt
│   │   filelist.txt
│   │
│   ├───FolderA
│   │       filelist.txt
│   │
│   └───FolderB
│       │   filelist.txt
│       │
│       └───FolderB1
│               doc1b.txt
│               doc2b.txt
│
├───Folder2
│   │   filelist.txt
│   │
│   ├───FolderA
│   │       filelist.txt
│   │
│   └───FolderB
│           filelist.txt
│
└───Folder3
        filelist.txt
0
codewario On

While I normally avoid external commands when a proper solution can be found with PowerShell cmdlets, tree /f already does this for you. There is some funkiness with relying on transcripts to provide the directory tree but you should be able to manually redirect the output to a file without issue:

cd /path/to/base/folder
tree /f > filelist.txt

This will create filelist.txt relative to the directory you ran tree /f from, and redirect the output to filelist.txt. Note that if filelist.txt exists already in the folder tree, it will be enumerated with the rest of the files.