Root Loop
Root Loop

Reputation: 3162

Powershell: creating folder structure based on month and year and copying file accordingly

I have a folder contains a lots of files created over the years. Lets call it folder A, in Folder A i have files created on 2012,2013,2014 and so on, files will continuously created in this folder. There is no structure under Folder A, just bunch of files.

Task1:

Now I have to make a copy of those files based on month and year, I have a folder B, in this Folder B, First I d like to have a level by year, then under each year, I will have folders by month, so all the files from Folder A will be copied into each location in folder B based on their date of Creation.

--B
---2013
--------Jan
--------Feb
--------Mar
---2014
--------Jan
--------Feb
--------Mar
.......

Task2:

This script will be scheduled 3 times per day, each time when it runs, it has to compare "last modify date" between source and destination, if "last modify date" on source is newer than destination, then copy the modified file to destination with "original name + modified date" as new file name. Skip if the files remain untouched.

Upvotes: 0

Views: 3143

Answers (4)

Patrick Mcvay
Patrick Mcvay

Reputation: 2281

Ok, this has been reworked. It is the most efficient way I can think to do this with this technology.

$indexFilePath = "C:\Folder B\FileUpdateTracker.Json"

if ((Test-Path -Path $indexFilePath) -eq $false)
{
    [psobject]@{
                LastUpdate = [datetime]::MinValue.Date;
               } | ConvertTo-Json | Out-File -FilePath $indexFilePath -NoClobber
}

$oldFileIndex = Get-Content -Path $indexFilePath | ConvertFrom-Json

$testFiles = @(Get-ChildItem -Path "C:\Folder A" | Where { $_.LastWriteTime.Date -ge $oldFileIndex.LastUpdate })


if ($testFiles.Count -eq 0)
{
    return
}

$fileIndex = [psobject]@{
                            LastUpdate = (Get-Date).Date;
                        }

foreach ($file in $testFiles)
{
    $year = $file.CreationTime.Year
    $month = $file.CreationTime.ToString("MMM")

    $archivePath = "C:\Folder B\$year\$month"

    mkdir -Path $archivePath -ErrorAction SilentlyContinue

    $copiedFileName = $null

    if ((Test-Path "$archivePath\$($file.Name)") -and $file.LastWriteTime.Date -ge $oldFileIndex.LastUpdate)
    {
        $copiedFileName = "$archivePath\$($file.Name.Replace($file.Extension, "_$($file.LastWriteTime.ToString("MM-dd-yy_hh-mm"))$($file.Extension)"))"
    }else{
        $copiedFileName = "$archivePath\$($file.Name)"
    }

    Copy-Item -Path ($file.FullName) -Destination $copiedFileName
}


$fileIndex | ConvertTo-Json | Out-File -FilePath $indexFilePath -Force

Upvotes: 0

rokumaru
rokumaru

Reputation: 1244

Another way is to use BitsTransfer.

$dirA = "C:\Test\A"
$dirB = "C:\Test\B"

$params = Get-ChildItem $dirA -File | foreach {
    $destFile = [IO.FileInfo]("{0}\{1:yyyy}\{1:MMM}\{2}_{3:yyyyMMddhhmmss}{4}" -f $dirB,$_.CreationTime,$_.BaseName,$_.LastWriteTime,$_.Extension)
    if($destFile.Exists) { return }
    $destFile.Directory.Create()
    @{ Src = $_.FullName; Dest = $destFile.FullName }
}

if(!$params) { return }
Start-BitsTransfer -Source $params.Src -Destination $params.Dest -DisplayName "Backup"

Upvotes: 0

user6811411
user6811411

Reputation:

The most effecient method is IMO

  • to create a calculated property from CreationDate year and month
  • Group by that property
  • create target folder if non existent
  • move files of that group

## Q:\Test\2019\04\22\SO_55798207.ps1

$Source = "X:\FolderA"
$Target = "Y:\FolderB"

Push-Location $Source

Get-ChildItem $Source -File |
  Select-Object *,@{n='YearMonth';e={$_.CreationTime.ToString('yyyy\\MMM')}} |
    Group-Object YearMonth | ForEach-Object {
      $NewFolder = Join-Path $Target $_.Name
      If (!(Test-Path $NewFolder)){New-Item $NewFolder -ItemType Directory|Out-Null}
      $_.Group | Copy-Item -Destination $NewFolder
    }
Pop-Location

Upvotes: 1

Walhalla
Walhalla

Reputation: 396

This should fullfil your request:

$Files = Get-ChildItem -Path "C:\FolderA"

Foreach ($File in $Files) {

   $File | Copy-Item -Destination "C:\FolderB\$( $File.LastWriteTime.Year )\$( $File.LastWriteTime.ToString("MMM") )"

}

Upvotes: 0

Related Questions