Every once in a while I come up with a need for something a little out of the ordinary, in this instance I was moving backups from one machine to another. Robocopy is the obvious tool of choice to do this. Trouble was that the backups were not all within a single directory, rather they were in multiple subdirectories. Robocopy will of course handle this with the /S switch. What Robocopy can’t handle is the fact that I want only the most recent file from each one of those subdirectories, not all of them (in this case I just wanted to move the most recent differential backup from one location to another).
I figured I could sit down and query msdb for this information and dump that out. I mean it works, it’s functional and does exactly what I would need it to do. Where’s the fun in that though, really? Add to that it would only handle SQL backups, what if I had a need to do the same thing later on for other types of files? The TSQL query wouldn’t work for me then.
PowerShell to the rescue
Seriously, I think that I’m going to get a cape for PowerShell that it can wear around the place as it’s that damn super (although I am not sure that I want to see it’s underwear outside its pants).
In this example I’m going to be working from C:Temp on my local machine.
Within C:Temp there are two folders and a subfolder:
Each of these folders contains a couple of files:
To grab the most recent file from a particular folder is a quick one liner:
dir c:tempsubfolder2 | sort-object {$_.LastWriteTime} -Descending | select-object -First 1
That is the basis for the rest of the script. Essentially everything else just handles recursing through the subdirectories to grab this information:
cls
$Path = 'C:Temp' #Root path to look for files
$DestinationPath = 'RemoteD$' #Remote destination for file copy
#Grab a recursive list of all subfolders
$SubFolders = dir $Path -Recurse | Where-Object {$_.PSIsContainer} | ForEach-Object -Process {$_.FullName}
#Iterate through the list of subfolders and grab the first file in each
ForEach ($Folder in $SubFolders)
{
$FullFileName = dir $Folder | Where-Object {!$_.PSIsContainer} | Sort-Object {$_.LastWriteTime} -Descending | Select-Object -First 1
#For every file grab it's location and output the robocopy command ready for use
ForEach ($File in $FullFileName)
{
$FilePath = $File.DirectoryName
$FileName = $File.Name
Write-Output "robocopy $FilePath $DestinationPath $FileName /R:6 /W:30 /Z"
}
}
Running this gives the results:
Quick and easy, does just what it says on the box. Feel free to download CopyNewestFileFromSubDir.ps1 and give it a try. Let me know what enhancements you put around it (here’s a quick one, to limit the type of files evaluated change !$_.PSIsContainer to $_.Extension –eq “.bak” )