Home > Back-end >  Powershell copy files based on last modified date & rename them afterwards
Powershell copy files based on last modified date & rename them afterwards

Time:03-22

i´ve got little bit stucked with my powershell script.

I would like to run through multiple folders, grab files based on their last modified date and copy them to a new location. There i have to rename them to a specific convention based on it´s original Filename. What i wrote only runs through the first part and copy files successfully but not rename them afterwards. Of course when i run the script a second time it renames the files...

File convention is: 120_00001_000_002222_202201_20220124_121833_Formular - Copy.pdf

result should be 2222_120_Memory 01-2022_012022.pdf

this is what i got already

$path = "G:\Temp"
$Target = "K:\Local"
$Max_days = "-60" #Max Days past
$Curr_date = Get-Date
$files = get-childitem $Target *.pdf


Get-ChildItem -Path $path -Recurse -Filter 120_*.pdf |
Where-Object {
    $_.LastWriteTime `
        -gt (Get-Date $Curr_date.AddDays($Max_days)) `
             } | ForEach-Object { $_ | Copy-Item -Destination $Target  -Force -PassThru } 

    foreach($pdf in $files)
 {
      $split = $pdf.name -replace ".pdf" -split "_"
      $newname = "$($split[3].TrimStart("0"))_$($split[0])_$("Memory") $($split[4].Substring($split[4].Length - 2, 2))-$($split[5].Substring(0,4))_$($split[4].Substring($split[4].Length - 2, 2))$($split[5].Substring(0,4))$($pdf.Extension)"
      write-verbose "Original: $($pdf.name)" -verbose
      write-verbose "NewName: $($newname)" -verbose
      Rename-Item $pdf.FullName -NewName $newname -verbose 
                }

Thanks in adavnced

Edited the Question to more precision.

CodePudding user response:

As commented, you could do this in one loop and rename the file while copying.

Try below:

$path     = 'G:\Temp'
$Target   = 'K:\Local'
$Max_days = -60   # Max Days in the past
$refDate  = (Get-Date).AddDays($Max_days).Date  # set to midnight

# get the files of interest
Get-ChildItem -Path $path -Recurse -Filter '120_*_*_*_*_*_*_*.pdf' -File |
Where-Object { $_.LastWriteTime -gt $refDate } | 
ForEach-Object { 
    # rename the file to match the new file naming convention
    $split = $_.BaseName -split "_"
    # just for clarity, using this example: 
    # '120_00001_000_002222_202201_20220124_121833_Formular - Copy.pdf'

    # $split[0]  --> 120                used unchanged
    # $split[1]  --> 00001              unused
    # $split[2]  --> 000                unused
    # $split[3]  --> 002222             used without leading zeros
    # $split[4]  --> 202201             used, only the last two digits (month)
    # $split[5]  --> 20220124           used, only the first four digits (year)
    # $split[6]  --> 121833             unused
    # $split[7]  --> Formular - Copy    unused

    # these elements are used more than once, so for convenience store in separate variables
    $month = $split[4].Substring($split[4].Length - 2, 2)
    $year  = $split[5].Substring(0,4)

    # construct the new file name
    $newName = '{0}_{1}_Memory {2}-{3}_{2}{3}{4}' -f $split[3].TrimStart("0"),
                                                     $split[0],
                                                     $month,
                                                     $year,
                                                     $_.Extension
    # construct the complete target path and filename
    $targetFile = Join-Path -Path $Target -ChildPath $newName
    # now copy the file with a new name to the target folder
    $_ | Copy-Item -Destination $targetFile -Force
}

I've used the -f Format operator to construct the new filename, because I believe this makes the code easier to read.

I did not take into consideration that naming collisions might occur (file with that new name already in the target folder).
If that can happen, you need to tell us what strategy to use.
Perhaps append an index number to the file in brackets like Windows does?

  • Related