0

I am working on a PS script to move the 5 newest files by file type from a source directory to a destination directory while preserving the subfolder structure. For example I would like to move any file starting with AB_ from ParentFolder1\FolderA, ParentFolder1\FolderB, ParentFolder1\FolderC, etc to ParentFolder2\FolderA, ParentFolder2\FolderB, ParentFolder2\FolderC.

ParentFolder1

--FolderA

----AB_1234.txt

----AB_5678.txt

----XY_9876.txt

----XY_9876.txt

--FolderB

----AB_1234.txt

----AB_5678.txt

----XY_9876.txt

----XY_9876.txt

--FolderC

----AB_1234.txt

----AB_5678.txt

----XY_9876.txt

----XY_9876.txt

Is there a way to tie this into a for loop? Here is what I have so far:

$source = "C:\Test"
$dest = "E:\archive"
$AB = Get-ChildItem -Path $source -include AB_* -Recurse | Where-Object {-not $_.PsIsContainer}
$XY = Get-ChildItem -Path $source -include XY_* -Recurse | Where-Object {-not $_.PsIsContainer}
$keep = 5
$logfile = "E:\_archive\temp\log_{0:MM-dd-yyyy}.log" -f (Get-Date)

if ($AB.Count -gt $keep) {
    $AB | Sort -property LastWriteTime | Select-Object -First ($AB.Count - $keep) | Move-Item -destination $dest\AB -Force -Verbose
    }
Else
    {"No AB_ files to archive." | Out-File $LogFile -Append -Force}

if ($XY.Count -gt $keep) {
    $XY | Sort -property LastWriteTime | Select-Object -First ($XY.Count - $keep) | Move-Item -destination $dest\XY -Force -Verbose
    }
Else
    {"No XY_ files to archive." | Out-File $LogFile -Append -Force}

2 Answers 2

2
function Move-Newest-Files 
{
    param (
        [parameter(Mandatory = $true)] [string] $source,
        [parameter(Mandatory = $true)] [string] $destination,
        [parameter(Mandatory = $true)] [array] $filter,
        [parameter(Mandatory = $false)][int] $keep = 5
    )

    try
    {
        $source = Resolve-Path $source

        $list = Get-ChildItem -Path $source -Include $filter -Recurse -Force |
            Where-Object { -not $_.psIsContainer } |
            Sort-Object -property LastWriteTime -descending | 
            Select-Object -First $keep

        foreach ($file in $list)
        {
            $destfile = $file -replace [regex]::Escape($source), $destination
            $destpath = Split-Path $destfile -Parent

            if (!(Test-Path $destpath))
                { $null = New-Item -ItemType Container -Path $destpath }

            Move-Item $file -Force -Destination $destfile
        }
    }

    catch
    {
        Write-Host "$($MyInvocation.InvocationName): $_"
    }
}

Move-Newest-Files . "D:\xyzzy" @("*.cs", "*.txt", "*.exe") 10
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks David. Could you please define the $filter and $file variables for me?
$filter is an array build with file extensions for the files you want to keep: something like this @(".cs", ".txt", ".exe") or this @(".*")
0

You might be better off using Robocopy.

2 Comments

The main reason I didn't go with xcopy or robocopy is that I couldn't find a way to keep the newest 5 files and move the rest. Is there a way to do this with Robocopy?
Sorry, I didn't notice that bit about the newest 5 files.

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.