Copy most recent file from folder to destination - powershell

I need some assistance with powershell . My experience is very limited as I'm a sql server dba. What I am currently doing is migrating databases across from 2000 to 2008. I want to automate the .bak copy from source to destination so I don't need to go into each folder and copy and then paste. So let me give the picture. The source directory has folders a b c d. I want the script to read from each folder or ideally specify the folder names and get the most recent
.Bak full backup by date and copy to a destination. The destination will have the same folders so folder a's backup copied to destination folder a will be great. Afterwards I want to do the same but change my search from full backup search to differential. Any help is appreciated.

This is how I would address it. The variables for folderpath and destination path are the root folders and the variable for childfolders list out each folder to search.
Clear-Host
$ChildFolders = #('A', 'B')
for($i = 0; $i -lt $ChildFolders.Count; $i++){
$FolderPath = "D:\BackupSource\" + $ChildFolders[$i]
$DestinationPath = "D:\BackupDestination\" + $ChildFolders[$i]
gci -Path $FolderPath -File | Sort-Object -Property LastWriteTime -Descending | Select FullName -First 1 | %($_){
$_.FullName
Copy-Item $_.FullName -Destination $DestinationPath
}
}

Given this structure, meaning all folders exist.
├───destination
│ ├───A
│ └───B
└───source
├───A
└───B
You can do the following:
$folders = #('A', 'B')
$source = 'source'
$destination = 'destination'
$filter = '*.bak'
$folders | foreach {
$source_path = [io.path]::combine($source, $_)
$destination_path = [io.path]::combine($destination, $_)
gci $source_path -File -Filter $filter | sort -Property LastWriteTime -Descending |
Select -first 1 | copy -Destination $destination_path
}
It gets all files matching your filter, sorts them in descending order by LastWriteTime, picks the newest and copies it to your destination.

Related

Copy files into newly created folders on partial filename match

Hi all reaching out because I've reached the limits of my powershell knowledge.
I have a directory that has over 200,000 files, I need to copy all files that have a partial match to the filename into folders that I have already created using this script
Set-Location "C:\Users\joshh\Documents\Testing Environment"
$Folders = Import-Csv "C:\Users\joshh\Documents\Weichert.csv"
ForEach ($Folder in $Folders) {
New-Item "myfilepathhere\$($Folder.folderName)" -type directory
}
UPDATED:
Here is a sample of the filenames:
TH-246-02050-LOL-SQ-ALT2.png
TH-246-02050-WHT-H.png
TH-247-02050-EMB-LOD.png
TH-246-02050-LOL-H-ALT2.png
TH-246-02050-LOL-SQ.png
TH-246-02050-LOL-SQ-ALT.png
TH-247-02050-EMB-LOD-ALT.png
TH-247-02050-EMB-LOL.png
TH-247-02050-EMB-LOL-ALT.png
TH-247-02050-LOD-H.png
Above is an example of what the filenames look like, I need to copy all files containing -EMB- and move them into folders in another directory that match the first 12 characters of that filename (ex. TH-247-02050)
UPDATED:
And if a folder doesn't exist create a folder with the first 12 characters of the filename.
Mind you the first 12 characters have many variants some start with RM, KW, etc.
This is what I have so far and what I know but I know the Move-Item portion isn't exactly what I want it to do
$source = "targetPath"
$destination = "targetPath2"
$embFiles = #(Get-ChildItem ${source}/*EMB* -File | Select-Object -ExpandProperty FullName)
foreach($file in $embFiles) {
if($file | Where-Object { $_ -clike "*EMB*" }){
Move-Item -Path $source -Destination $destination
}
}
Any and all help would be GREATLY appreciated!
Here is one way you could do it:
Get all files that contain -EMB- in their names: -Filter *-EMB-* -File.
Group all this files by everything before -EMB-, here we can use Group-Object -AsHashTable and a calculated expression using Regex.Match. See https://regex101.com/r/iOoBJS/1 for details.
Loop through the Keys of the hash table, each Key will be the Name Destination folder of the group of files (i.e.: TH-247-02050).
Join the destination path ($destinationPath2) with the name of the destination folder ($folder), here we can use Join-Path and check if this joined path exists, if it doesn't, create a new folder with New-Item.
Lastly, we can move all the files (the Values of each Key from the hash table) to their corresponding destination.
$source = "targetPath"
$destination = "targetPath2"
$map = Get-ChildItem $source -Filter *-EMB-* -File | Group-Object -AsHashTable -AsString {
[regex]::Match($_.BaseName, '(?i).+(?=-EMB-)').Value
}
foreach($folder in $map.Keys) {
$d = Join-Path $destination -ChildPath $folder
$d = New-Item $d -ItemType Directory -Force
# -WhatIf can be removed once you have checked the script is doing what you want
$map[$folder] | Move-Item -Destination $d -WhatIf -Verbose
}
-AsString is needed in Windows PowerShell due to a bug.

compare 2 folders and copy the difference in the 3rd folder with the same folder structure recursively using Powershell

Here what I'm trying to do and this is my second post on the same issue, I'm trying to compare 2 folders and copy the difference in the 3rd folder with the same folder structure recursively.
Here is the Powershell script which I receive from an another post (how to copy updated files to new folder and create directory as source if not exist?). This code does everything I need but I have one problem, with the -passthru arguement, it take the file which ever is new in the "folder 2" as well. What I need is what ever files are different in Folder1 from Folder2 alone to be copied over to Folder3. I tried and could not make it work. Any help will be great.
$newdir = "M:\Technical\foldercompare\folder1"
$olddir = "M:\Technical\foldercompare\folder2"
$diffdir = "M:\Technical\foldercompare\folder3"
#Get the list of files in oldFolder
$oldfiles = Get-ChildItem -Recurse -path $olddir | Where-Object {-not ($_.PSIsContainer)}
#get the list of files in new folder
$newfiles = Get-ChildItem -Recurse -path $newdir | Where-Object {-not ($_.PSIsContainer)}
Compare-Object $oldfiles $newfiles -Property LastWriteTime,Length -Passthru | sort LastWriteTime | foreach {
$fl = (($_.Fullname).ToString().Replace("$olddir","$diffdir")).Replace("$newdir","$diffdir")
$dir = Split-Path $fl
If (!(Test-Path $dir)){
mkdir $dir
}
copy-item $_.Fullname $fl
}

Filter all files recursively in a directory and then move them to a new set of folders each with a limit of files per directory

Sorry for the long title, just trying to be specific.
Here's my scenario today (as the title alludes):
Root Dir has x amount of folders, say 20. Each folder has files and possible sub-folders. I know that I only care about the files in any folder with "Hold" in the folder name.
I need to target all files, no matter the type, in the folders and subs. I then need to move the target files to new folders in the root dir. Each folder must only house 50,000 files and then roll over to the next folder for the next 50k. That process will repeat until all the targets have been moved to their new dir.
Here's the PS code I have so far:
#SETUP
$FileDir = GCI -Path C:\TEST -Filter 'Hold*' -Directory -Recurse
$FilesinHOLD = GCI -File -Path $FileDir.FullName -Recurse
$NewDir = 'C:\TEST\Limited'
$Limit = '50000'
#Execution
$FilesinHOLD | Select-Object -First $Limit | Move-Item -Destination $NewDir
Where I'm left is looking for the mechanism to auto-create a new "Limited" folder and put 50k in there and then repeat the process. I was wondering if it would be possible to just render the same name simply followed by (2) and then (3) and so on automatically as the default behavior in Windows Explorer..? It would look like this:
C:\TEST\Limited
C:\TEST\Limited(2)
C:\TEST\Limited(3)
I would finish up by running back through and deleting the now empty "HOLD" directories from which I pulled the files from after verifying they are empty via GCI or Measure-Object.
Thanks in advance for your input.
-CE
Rather than grabbing all the files then removing them from the array, I would move them as I recurse the directories, then loop on that:
$rootDir = 'C:\TEST\Limited'
$NewDir = $rootDir
$Limit = '50000'
$filesMoved = $Limit
$folderCnt = 1
while($filesMoved -ge $limit)
{
$filesMoved = GCI -Path C:\TEST -Filter 'Hold*' -Directory -Recurse | GCI -File -Recurse | Select-Object -First $Limit | Move-Item -Destination $NewDir -passthru | measure | select -expand count
$folderCnt += 1
$newDir = $rootDir +"($folderCnt)"
}

PowerShell move most recent file from each folder

I need some assistance with powershell - I would like to search within all subfolders of a particular folder, and copy the latest file from each subfolder to a new folder every day at 9.00 AM. So, I want to search within folder A's subfolder a, b and c to pick out the latest file in a, b and c each, and move all three files into outside folder B (a single folder). I am new to PowerShell - any help is appreciated. I've basically tried to use this but it creates a backup: Copy most recent file from folder to destination
Clear-Host
$ChildFolders = #('In_a', 'In_b', 'In_c')
for($i = 0; $i -lt $ChildFolders.Count; $i++){
$FolderPath = "C:\FolderA\" + $ChildFolders[$i]
$DestinationPath = "C:\FolderB\" [$i]
gci -Path $FolderPath -File | Sort-Object -Property LastWriteTime -Descending | Select FullName -First 1 | %($_){
$_.FullName
Copy-Item $_.FullName -Destination $DestinationPath
}
Gets subfolders
Gets all files in subfolders
Sorts files by Creation Date into a array
Gets first Entry
Moves file to Destination directory
*It will overwrite files with the same name in the destination folder
Function Get-LatestFiles($SourceFolder,$Destination){
$Subfolders = Get-ChildItem $SourceFolder -Directory
[System.Collections.ArrayList]$SubFoldersExpanded = new-object System.Collections.ArrayList
Foreach($SubFolder in $SubFolders){
$SubFolderExpanded = $Subfolder | %{(Get-ChildItem $_.FullName -File -Depth 1 | Sort-Object -Property CreationTime -Descending)}
if($SubFolderExpanded.Count -gt 0){
$SubFolderExpanded[0] | %{Move-Item $_.FullName -Destination $Destination -force}
}
}
}
Get-LatestFiles -SourceFolder C:\test -Destination C:\test01

find latest file name and copy as renamed file in the same folder

I see some kind of similar posts but unfortunately this is not working for me so far. I would like to get the latest backup file (randomly generated) and then copy and rename the file in the same folder with fixed name so that I can schedule the restore job.
Backup files are like:
Fin123.bak
Fin125.bak
Sales456.bak
HRF100.bak
I would like to get the latest file (by creation date) and then copy and rename the file like Fin.bak. In the above files, Fin125.bak is latest backup file which I would like to copy and rename as Fin.bak. The powershell script should ignore all other files like Sales, HR, etc. Only files starting with Fin and having the latest creation date.
Any help is greatly appreciated.
Thanks
Muhammad
This should do the trick.
$bak_path = "path_to_backup_folder"
get-childitem -path $bak_path -Filter "Fin?*.bak" |
where-object { -not $_.PSIsContainer } |
sort-object -Property $_.CreationTime |
select-object -last 1 |
copy-item -Destination (join-path $bak_path "FIN.BAK")
Going through it;
$bak_path = "path_to_backup_folder" declare the path to the backup directory as a constant.
get-childitem -path $bak_path -Filter "Fin?*.bak" return a set of objects in folder $bak_path that match the filter "Fin?.bak". The '?' is used to ensure only files with at least one character between 'fin' and '.bak' match.
where-object { -not $_.PSIsContainer } removes any directory objects (just in case).
sort-object -Property $_.CreationTime sorts the list so that the newest file is last in the collection.
select-object -last 1 picks off the last item (ie newest file) and finally
copy-item -Destination (join-path $bak_path "FIN.BAK") copies the last item as FIN.BAK to the same directory
This will work for grabbing the most recent file of the .bak extension.
$OriginalDir = "E:\"
$BackupDir = "H:"
#After the -Name can be changed for whatever you need to backup.
$LatestFile = Get-ChildItem -Path $dir -Name *.bak | Sort-Object LastAccessTime -Descending | Select-Object -First 1
Copy-Item -path "$OriginalDir\$LatestFile" "$BackupDir\$LatestFile"
Wesley's script works OK but have a little error, it use $dir but must be $OriginalDir
$LatestFile = Get-ChildItem -Path $OriginalDir -Name *.bak | Sort-Object LastAccessTime -Descending | Select-Object -First 1
this works well- but you need to change to Last--becoz- list is descending
Select-Object -Last 1