Search code examples
powershellmove

Powershell Move Most recent File


I have a directory lets call it C:\MoveFile within this directory are thousands of files similarly named

  • Name Date Modified
  • Dog_123123_Grey.doc 18/11/2015
  • Dog_123123_Grey (2).doc 19/11/2015
  • Dog_123123_Grey (3).doc 17/11/2015
  • Cat_123123_Blue (3).doc 01/01/2015
  • Cat_123123_Pink (6).doc 07/04/2015
  • Cat_123123_Pink (7).doc 10/04/2015

Now if the version number in the file name was consistently numbered (2) etc it would be easy, however what I want to do is have powershell run through the items in the directory and move the most recent file based on the date modified to a new file location so that from the list provided the new directory will contain.

Name Date Modified

  • Dog_123123_Grey (2).doc 19/11/2015
  • Cat_123123_Blue (3).doc 01/01/2015
  • Cat_123123_Pink (7).doc 10/04/2015

Now as far as my head can get with this is,

gci C:\MoveFile\*.doc | sort LastWriteTime -desc | select -first 1 | cpi -dest c:\NewDirectory

Which I haven't tested as I know its not complete and will not do what I need it to do, being honest there I know that somehow I need to ignore anything that is in the brackets e.g. (3) which I don't know how to do. I had considered looking at 'somehow' only looking at the first 15 digits but some of the file names may be longer or shorter than this.

Scratching my head in frustration, anyone with more experience than I have any ideas?


Solution

  • What you might want to do is:

    1. Group files by name (excluding the version in the filename)
    2. Sort the files in each group individually
    3. Pick the most recent from each group

    To get the filename without the version number, we can use the -replace regex operator to remove any set of parentheses containing one or more digits at the end of the BaseName string (the filename exlcuding the file extension):

    PS C:\> 'Cat_123123_Blue (3)' -replace '\(\d+\)$',''
    Cat_123123_Blue
    

    So, to group them by this string, we do:

    $FileGroups = Get-ChildItem -Path C:\Movefile\ -Filter *.doc |Group-Object { ($_.BaseName -replace '\(\d+\)$','').Trim() }
    

    Then iterate over our array of groups:

    $FileGroups |ForEach-Object { 
        # Sort each group, grab the most recent file
        $RecentFile = $_.Group |Sort-Object LastWriteTime -Descending |Select -First 1 # Copy it
        Copy-Item $RecentFile.FullName -Destination C:\NewFolder\
    }