2

I am trying to move thousands of files into YYYY-MM folders, using a scheduled task which runs every night. The files are currently stored here:

C:\Users\USER\Desktop\New folder

I want them to be stored like this:

C:\Users\USER\Desktop\New folder\YYYY\MM\

eg:

C:\Users\USER\Desktop\New folder\2019\05

The script would create the YYYY\MM folders if they dont already exist. The file name is in the following format:

Status_20200116_001058.txt

So for the above file, YYYY is 2020 and the MM is 01

I found a PS script on Stack and amended it to the below, but I have not used PS much before and am a bit lost:

$Files_Folder = "C:\Users\USER\Desktop\New folder"
get-childitem | % {
    $file = $_.FullName
    $month = $date.month
    $year = $date.year

    new-item -type Directory -path "$Files_Folder\$year\$month"
    move-item $file "$Files_Folder\$year\$month"
}

Running the above results in PS creating a whole bunch of folders and files in the location above, which I cannot delete:

enter image description here

Any help would be most appreciated

Edit: So I tried the script from @Wasif Hasan like this:

$Files_Folder = "C:\Users\USER\Desktop\New folder1"
get-childitem | % {
    $file = $_.FullName
    $month = $file.substring(12, 2)
    $year = $file.substring(8, 4)
    $folder = Join-Path -Path "$($Files_Folder)" -ChildPath "$($Year)"
    $folder = Join-Path -Path "$($folder)" -ChildPath "$($Month)"
    $Exists = Test-Path "$($Folder)"
    If (!$Exists) { New-Item -Type directory -Path "$($Folder)" }
   Move-Item "$($File)" "$($Folder)"
}

However I just get a bunch of errors in PS:

enter image description here

Edit: Just tried the script by @Pavithran G, amended for using a Year and Month variable instead of Month and Date:

$loc = "C:\Users\nazadmin\Desktop\New folder1"
$files = Get-ChildItem -Path $loc
for ($i=0; $i -lt $files.Count; $i++) 
{
$outfile = $files[$i].FullName
$filename = Split-Path -Path $outfile -Leaf -Resolve
$Year = $filename -replace "Status_\d{0}(\d{4})[\d_]*.txt",'$1'
$Month = $filename -replace "Status_\d{4}(\d{2})[\d_]*.txt",'$1'
$folder = Join-Path -Path  $loc -ChildPath $Year
$folder = Join-Path -Path $folder -ChildPath $Month
$Exists = Test-Path $folder
If (!$Exists) 
{ 
    New-Item -Type directory -Path $folder 
}
Move-Item $outfile $folder
}

This works perfectly!

Edit: Just realised that if the YY folder exists already, then the script tries to create another YY folder within the YY folder, and throws an error:

Move-Item : Access to the path 'C:\Users\USER\Desktop\New folder1\2018' is denied.
At line:14 char:10
+ Move-Item <<<<  $outfile $folder
+ CategoryInfo          : WriteError: (C:\Users\USER...ew folder1\2018:DirectoryInfo) [Move-Item], IOException
+ FullyQualifiedErrorId : MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand

Any way I can avoid this situation?

Edit: Will post a new question to make it clearer Cheers

Naz
  • 525
  • 2
  • 9
  • 21
  • FYI you can't create folder in windows with filename that contains like any of the following characters:` \ / : * ? " < > |`.So you can't able create folder name like 2019\05..You want in any other format ? – pavithran G Jan 17 '20 at 10:52
  • Thats the folder path, not the folder name. So the path goes to folder 2019, then folder 05 - based on year and month in filename – Naz Jan 17 '20 at 13:05

2 Answers2

1

Below script will create folder based on the filename present in that.So,no need to add for scheduled task, you can run at any time , it will automatically create folder,but don't change the format of the filename which you mentioned earlier.

$loc = "C:\Users\USER\Desktop\New folder"
$files = Get-ChildItem -Path $loc
for ($i=0; $i -lt $files.Count; $i++) 
{
$outfile = $files[$i].FullName
$filename = Split-Path -Path $outfile -Leaf -Resolve
$Month = $filename -replace "Status_\d{4}(\d{2})[\d_]*.txt",'$1'
$date = $filename -replace "Status_\d{6}(\d{2})[\d_]*.txt",'$1'
$folder = Join-Path -Path  $loc -ChildPath $Month
$folder = Join-Path -Path $folder -ChildPath $date
$Exists = Test-Path $folder
If (!$Exists) 
{ 
    New-Item -Type directory -Path $folder 
}
Move-Item $outfile $folder
}

Make sure ,run the Powershell script in Admin mode because sometimes it need administrator access to move or copy file

pavithran G
  • 112
  • 2
  • 13
  • Thanks for this @pavithran G, I have amended this slightly to add a $Year variable, as I am storing files in $Year then $Month folders, I have added that into the main post – Naz Jan 20 '20 at 10:14
0

$date is not declared as a date variable (Get-Date). Use Join-Path to safely create paths and you have not used Test-Path check the folder existence. Use this:

$date = Get-Date
$Files_Folder = "C:\Users\USER\Desktop\New folder"
get-childitem | % {
    $file = $_.FullName
    $month = $date.month
    $year = $date.year
    $folder = Join-Path -Path "$($Files_Folder)" -ChildPath "$($Year)"
    $folder = Join-Path -Path "$($folder)" -ChildPath "$($Month)"
    $Exists = Test-Path "$($Folder)"
    If (!$Exists) { New-Item -Type directory -Path "$($Folder)" }
   Move-Item "$($File)" "$($Folder)"
}
Wasif
  • 14,755
  • 3
  • 14
  • 34
  • He asking a folder name like '2019\05' as same folder ,not folder within folder – pavithran G Jan 17 '20 at 10:58
  • Hi @pavithranG thats the folder path, not the folder name. I will test this and reply back asap – Naz Jan 17 '20 at 13:06
  • Hi @Wasif Hasan the $month and $year variables need to be based on the filename, not the system date - is this possible please? So $year is based on the 8th to 11th characters in filename, $month is based on the 12th to 13th characters in filename – Naz Jan 17 '20 at 13:10
  • Actually just figured it out, to use substring function. I will test this and reply back – Naz Jan 17 '20 at 13:12
  • I get errors when using this, please see main post – Naz Jan 17 '20 at 13:23