PowerShell script to export a list of file names only with no file extension then output to a text file separate for each directory

Marc Kean picture Marc Kean · Jun 18, 2014 · Viewed 58.1k times · Source

I need a PowerShell script to export a list of file names only with no file extension then output to a text file separate for each sub-folder. I need to specify a parent directory in the script, then PowerShell needs to go off and create a separate text file for each sub folder using the the name of the sub folder for the text file name (with no spaces and lowercase). Then in each sub-folder based text file created, have a list of file names that are contained in each sub-folder with no file extension.

$files = Get-ChildItem -Path "M:\Music" -Recurse `
| Where-Object {`
    $_.DirectoryName -notlike "*Other\Children" -and `
    $_.DirectoryName -notlike "*Other\Numbers" -and `
    $_.Extension -eq ".mp3"}
#Now loop through all the subfolders
$folder = $files.PSisContainer
ForEach ($Folder in $files)
{
$ParentS = ($_.Fullname).split("\")
$Parent = $ParentS[@($ParentS.Length - 2)]
Select-Object BaseName > C:\Users\me\Documents\$parent.txt
}

OK, spent some more time on this, script is added below to the previous attempt. Seems I am very close this time, however writing to the text file at the end is not 100%, I was using Out-File before which was leaving a blank line at the bottom of each text file which I didn't want. Why I switched to [system.io.file]::WriteAllText and [system.io.file]::AppendAllText, however each of these have their idiosyncrasies which don't do what I need. In the Text file I need the list of files in one column with no blank lines.

$files = Get-ChildItem -Path "M:\Music" -Recurse `
| Where-Object {`
    $_.DirectoryName -notlike "*Other\Children" -and `
    $_.DirectoryName -notlike "*Other\Numbers" -and `
    $_.Extension -eq ".mp3"}
#Now loop through all the subfolders
$folder = $files.Directory
ForEach ($Folder in $files)
{
$ParentS = ($folder.Fullname).split("\")
$ParentT = $ParentS[(@($ParentS.Length - 2))]
$Parent = $ParentT.replace(' ','')
[system.io.file]::WriteAllText("C:\Users\me\Documents\$parent.txt", $folder.BaseName,                                            [System.Text.Encoding]::Unicode)
}

Answer

WiiBopp picture WiiBopp · Jul 12, 2014

What a good opportunity to show off the richness of Powershell and .NET working together.

First off, the easiest way to get the full names of all the subfolders of a folder is with a line like this:

$folders = (Get-ChildItem -Directory -Recurse M:\Music).FullName

-Directory limits what is returned to an array of DirectoryInfo object. By taking advantage of Powershell's ability to return only the FullName property, we can return an array of folder paths all in one statement

We can create the files listing the songs in the directory with just a few more lines of code:

foreach ($folder in $folders)
{
    $fileBaseNames = (Get-ChildItem $folder\*.mp3).FullName | % {[System.IO.Path]::GetFileNameWithoutExtension($_)}
    $catalogFileName = (Split-Path $folder -Leaf) -replace ' ',''
    if ($fileBaseNames)  {Set-Content -Path $folder\$catalogFileName.txt -Value $fileBaseNames}
}

We visit each subfolder and for every subfolder we:

  • Get an array of the mp3 file names (without file extension) in the current directory. (I love .NET's GetFileNameWithoutExtension method at times like this.
  • Create the file name for our catalog by isolating the current folder name (Split-Path -Leaf) and sucking out all the spaces by replacing each space with an empty string.
  • Finally if our list of songs isn't empty we save it off with Set-Content, a great way to save a list of anything.

It never ceases to amaze me how powerfull and concise Powershell is. The line creating the $fileBaseNames may be a little gnarly for some, but it would be an easy enough thing to turn the foreach-object construct into an easy to ready multiline foreach clause.