1

I have thousands of files spanning 5 years which I would like to move into year/month folders. The file names all end with

_yyyy_mm_dd_wxyz.dat

I'm looking for ideas on how I can generate such file folders and move the files into the appropriate folders yyyy/mm using the windows command shell.

2
  • bash or powershell? Commented Jul 23, 2018 at 19:16
  • with powershell Commented Jul 23, 2018 at 19:16

3 Answers 3

1

You'll need a Regular Expression with (capture groups) to extract year/month from the filename.
Assuming the year/month folder should be placed directly in files parent location.

untested with -Version 2

## Q:\Test\2018\07\23\SO_51485727.ps1
Push-Location 'x:\folder\to\start'
Get-ChildItem *_*_*_*_*.dat |
  Where-Object {$_.BaseName -match '_(\d{4})_(\d{2})_\d{2}_[a-z]+$'} | ForEach-Object {
    $TargetDir = "{0}\{1}" -f $Matches[1],$Matches[2]
    if (!(Test-Path $TargetDir)){MD $TargetDir | Out-Null}
    $_ | Move -Destination $TargetDir 
}

Sample tree /f after running the script on my ramdriive:

PS A:\> tree /F
A:.
├───2017
│   └───07
│           test_2017_07_24_xyz.dat
└───2018
    └───07
            test_2018_07_24_xyz.dat
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. I tried your script. "-Files" in the second line throws an error. Is it equivalent to the file path?
@Buzz: Sounds like you're using PowerShell v2 - if so, please add that tag to your question.
Changed the script above to be compatible with version 2.
@LotPings awesome. Your solution works with minor changes. I added a missing underscore i.e. $.Basename to $_.Basename. Thanks.
0

I have created this little quick and dirty script. Things have been put in more variables than strictly needed, they could be combined in a single line, but I feel this adds clarity which I hope help you understand what happens.

As a note, I have used the date the item was last written to (created or edited). If you want only the date the file was created and not the time the file was last edited, you could change LastWriteTime to CreationTime

#Load all files from the folder you wish to move on
$items = Get-ChildItem -Path "C:\SomeFolder\RestofPathToYourFiles"

foreach($item in $items) {
    #Creates variables for year, month and day
    $FolderYear = "$($item.LastWriteTime.Year)"
    $FolderMonth = "$($item.LastWriteTime.Month)"
    $FolderDay = "$($item.LastWriteTime.Day)"

    #create variable with the new directory path
    $NewPath = $item.Directory.FullName + "\" + $FolderYear + "\" + $FolderMonth + "\" + $FolderDay

    #create variable with the new full path of the file
    $NewFullPath = $NewPath + "\" + $item.Name

    #test if the folder already is created, if not, create it
    if((Test-Path -Path $NewPath) -eq $false) {
        New-Item -Force -path $NewPath -Type Directory
    }

    #move the item to the new folder
    Move-Item -Path $item.FullName -Destination $NewFullPath -Force
}

5 Comments

IIUR year/month should be extracted from file name. The new folder name could be much easier formed with $item.LastWriteTime.ToString('yyyy\MM)`
Well yes and no. You want to make sure you can form a proper path. $item.LastWriteTime.ToString('yyyy\MM') Outputs: 2018M7 On my files at least. Also splitting things up makes it easier for someone new to learn imo :)
Even so, IMO too much code, also "$($item.LastWriteTime.Month)" will return an integer without leading zero.
Very true. Again, I choose to pen it out to make the code more clear as to what it does and showcase what you can pull out, as I mentioned you could indeed make it way way more efficient, even make it into a function, but then it would not be quick and dirty as I promised ;)
Indeed, my files were extracted from .7zip archives and ended up all having the same file creation and file modification times. In my case, LastWriteTime doesn't work.
0

At the simplest, I'd do something like the following:

  1. Determine the year and month related to a file
  2. See if a folder exists already. If not, create it
  3. Move the file

Example...

foreach ($file in $(ls .\stuff.txt)) {
    $m = $file.LastWriteTime.Month.ToString("00")
    $y = $file.LastWriteTime.Year
    $dir = "{0}-{1}" -f $y, $m
    New-Item -Name $dir -ItemType directory -ErrorAction SilentlyContinue | Out-Null
    Move-Item -Path $file.Fullname -Destination $dir
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.