1

I have tried to do my research, but I can't fathom this one out. I can combine multiple .txt files in a folder. no problem: dir C:\Users\XXXX\AC1\22JUN *.txt | get-content | out-file C:\Users\XXXX\22JUN\AC1_22JUN.txt

however, I have 14 Directories each with subdirectories. (months of the year), and this will only ever grow. How can I write it so that it will go into each directory AC1 - AC14 and then look into each folder JAN-DEC and in each subdirectory create a combined file for AC1_22JUN, AC2_22JUN AC1_22JUL, AC2_22JUL and so on and so on?

is there also a way to rename the output file with data, such as the number of .txt files that have been combined. i.e. AC1_22JUN_314.txt

many thanks in advance

Tjones
  • 25
  • 5

1 Answers1

2

What you need to do is iterate over all your directories and their subdirectories and run a particular command in each of them. This is easy enough to achieve using the cmdlet Get-ChildItem and a pair of nested foreach loops.

In addition, you need to count the number of text files you've processed so that you can name your aggregate file appropriately. To do this you can break your pipeline using the temporary variable $files. You can later begin a new pipeline with this variable and use its count property to name the aggregate file.

The code for this is as follows:

$dirs = Get-ChildItem -Directory
foreach ($dir in $dirs)
{
    $subdirs = Get-ChildItem $dir -Directory
    foreach ($subdir in $subdirs)
    {
        $files = Get-ChildItem *.txt -Path $subdir.fullname
        $name = "$($dir.name)_$($subdir.name)_$($files.count).txt"
        $files | Get-Content | Out-File "$($subdir.fullname)/$name"
    }
}

A few things to note:

  • The script needs to be run from the containing folder - in your case the parent folder for AC1-AC14. To run it from elsewhere you will have to change the first statement into something like $dirs = Get-ChildItem C:\path\to\container -Directory

  • Get-ChildItem is the same as the command dir. dir is an alias for Get-ChildItem. This is NOT the same as the variable $dir which I've used in the script.

  • Running the script multiple times will include any and all of your old aggregate files! This is because the output file is also a .txt file which is caught in your wildcard search. Consider refining the search criteria for Get-ChildItem, or save the output elsewhere.

  • Hi @equatorialsnowfall. many thanks for your fast and comprehensive response. I'm not sure what I am doing incorrectly, but it doesn't like it. the first error that i am getting is Get-ChildItem : Cannot find path 'C:\Powershell\Test_Container\22JUN' because it does not exist. At line:7 char:18 + $files = Get-ChildItem *.txt -Path $subdir + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (C:\Powershell\Test_Container\22JUN:String) – Tjones Jul 28 '22 at 10:39
  • I am also getting the out-file: could not find a part of the path Out-File : Could not find a part of the path 'C:\Powershell\Test_Container\22JUN\AC9_22JUN_0.txt'. At line:9 char:32 + $files | Get-Content | Out-File "$subdir/$name" – Tjones Jul 28 '22 at 11:07
  • 1
    @Tjones Looks like this is a compatibility problem between powershell versions. Casting a `System.IO.FileInfo` object to a string retrieves the entire path on Powershell 7, but only the name on Powershell 5. I've updated my answer, it should now work on either version. – equatorialsnowfall Jul 28 '22 at 14:41
  • Hi @equatorialsnowfall you have absolutely made my day! thank you ever so much for this. that has worked an absolute treat! – Tjones Jul 28 '22 at 15:16
  • 1
    Nicely done. Note that the insidious thing about stringification of `System.IO.FileInfo` instances in Windows PowerShell is that _situationally_ you get only the file name, other times you get the full name, _depending on the specifics of the `Get-ChildItem` call_ - see [this answer](https://stackoverflow.com/a/53400031/45375). Indeed, PowerShell (Core) now consistently stringifies to the full name. – mklement0 Aug 01 '22 at 18:42