powershell - Replace only old files with new files in destination directory - powershell

Hello All,
I wish to replace only the old file with new file
I tried
Set-Location C:\contains_newfolder_contents\Old Folder
Get-ChildItem | ForEach-Object {
if ((Test-Path 'C:\contains_newfolder_contents\Sample Folder\$_' ) -and
(.$_.LastWriteTime -gt C:\contains_newfolder_contents\Sample Folder\$_.LastWriteTime' )) {
Copy-Item .\$_ -destination 'C:\contains_newfolder_contents\Sample Folder'
}
}
Kindly correct me!

Here's a one-line solution. I used different folder names to make the example easier to read.
Get-ChildItem C:\temp\destination|foreach-object {$sourceItem = (get-item "c:\temp\source\$($_.name)" -erroraction ignore); if ($sourceItem -and $sourceItem.LastWriteTime -gt $_.lastwritetime) {Copy-Item -path $sourceItem -dest $_.fullname -verbose}}
For each existing file, it finds the matching file in the source folder. $sourcItem will be null if there is no matching source item. It proceeds to compare the dates and copy if the source date is newer.

you can do it too :
Get-ChildItem "C:\contains_newfolder_contents\Old Folder" -file | sort LastWriteTime -Descending | select -First 1 | Copy-Item -Destination 'C:\contains_newfolder_contents\Sample Folder'

Instead of making several reads to the source, I propose you make a lookup table and then these simple commands will achieve the desired results.
$source = 'C:\temp\Source'
$destintation = 'C:\temp\Destination'
$lookup = Get-ChildItem $destintation | Group-Object -Property name -AsHashTable
Get-ChildItem -Path $source |
Where-Object {$_.lastwritetime -gt $lookup[$_.name].lastwritetime} |
Copy-Item -Destination $destintation

Related

Powershell: Move all files except most recently modified?

Trying to simplify one of my archiving tasks, but I'm stumped on how to go about it. Basically, I just want Powershell to search a folder for files, and move all but the most recently modified (by LastWriteTime) to a backup folder.
I've searched around for solutions to this but every answer I've come across looks for the oldest file or depends on a specific file-naming convention to work.
Basically I want it to look at this this:
E:\ProjectFolder1\EDLs\File1.prproj (modified six days ago)
E:\ProjectFolder1\EDLs\File2.prproj (modified six hours ago)
E:\ProjectFolder1\EDLs\File3.prproj (modified six seconds ago)
Identify File3.prproj as the one that's most up-to-date, and move all the other files in the directory to another folder:
E:\Deep Storage\ProjectFolder1\EDLs\File1.prproj
E:\Deep Storage\ProjectFolder1\EDLs\File2.prproj
I know how to do everything except get it to compare the LastWriteTimes. Is there a way do get PS to do this?
EDIT with code sample
Get-ChildItem $sourceDir -Include $search -Recurse | Sort-Object LastWriteTime -Descending | Select-Object -Skip 1 | `
foreach{
$targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
New-Item -ItemType File -Path $targetFile -Force;
Move-Item $_.FullName -destination $targetFile -Force
}
EDIT with functional code:
$sourceDir = "E:\Test1\EDLs\"
$targetDir = "E:\Deep Storage\Test1\EDLs\"
$search = "*.prproj"
Get-ChildItem $sourceDir -Recurse -Directory | ForEach-Object {
$files = $_ | Get-ChildItem -File -Filter $search
if($files.Count -lt 2) {
return
}
$newPath = Join-Path $targetDir -ChildPath $_.FullName.Substring($sourceDir.Length)
$null = New-Item $newPath -ItemType Directory -Force
$files | Sort-Object LastWriteTime -Descending | Select-Object -Skip 1 |
Move-Item -Destination $newPath -Verbose -WhatIf
}
EDIT to show actual syntax for operating environment:
$sourceDir = "E:\Projects\Current\EDLs"
$targetDir = "E:\Deep Storage\Projects\Current\EDLs"
$search = "*.prproj"
Get-ChildItem $sourceDir -Directory | ForEach-Object {
# search only for files only 1 level under this folder
$files = Get-ChildItem $sourceDir -Filter *.prproj
# if there are at least 2 files here
if($files.Count -ge 2) {
# we dont need to create new folder here since these will go directly under
# destination folder so, we can just sort and skip first as in previous logic
$files | Sort-Object LastWriteTime -Descending | Select-Object -Skip 1 |
# then move them
Move-Item -Destination $targetDir
}
Ultimately the answer was a lot simpler than I thought it would be:
$sourceDir="E:\Test1\Test2"
# Where your files are
$targetDir="E:\Deep Storage\Test1\Test2"
# Where you want to send them
$search="*.ext"
# If applicable, what type of file you want to look for
Get-ChildItem -Path $sourceDir -Filter $search | Sort-Object |
Select-Object -SkipLast 1 | Move-Item -Destination $targetDir -Verbose -WhatIf
I use environment variables for my workflow so mine looks a little different, but this should be useful for anyone in the same situation.

Powershell test-path

Newbie help required here - I'm trying to search for the newest .csv file in F drive, then use Test-Path to check if that file is in the E drive. My script outputs the latest file name to screen which is correct - what I'm now trying to do is append $_latestFile.name to a Test-Path to see if this file is found in the folder in E drive.
Am I going about this the wrong way?
Thanks in advance.
$_sourcePath = "F:\"
$_destinationPath = "E:\"
$_FileType= #("*.*csv")
$_latestFile = Get-ChildItem -Recurse ($_sourcePath) -Include ($_FileType) | Sort-Object -Property $_.CreationTime | Select-Object -Last 1
$_latestFile.name
If your aim is to find a file in the $_destinationPath with the same name and modified date as the one you found on the $_sourcePath, you might do this:
$sourcePath ="F:\"
$destinationPath = "E:\"
$latestFile = Get-ChildItem -Path $sourcePath -Filter '*.csv' -File -Recurse | Sort-Object -Property $_.LastWriteTime | Select-Object -Last 1
Write-Host "Latest CSV file in $sourcePath is '$($latestFile.Name)'"
$destFile = Get-ChildItem -Path $destinationPath -Filter "$($latestFile.Name)" -File -Recurse | Where-Object { $_.LastWriteTime -eq $latestFile.LastWriteTime }
if ($destFile) {
Write-Host "Copy file found at '$($destFile.FullName)'" -ForegroundColor Green
}
else {
Write-Host "Could not find a file '$($latestFile.Name)' with the same modified date in '$destinationPath'"-ForegroundColor Red
}
I have changed the property CreationTime to LastWriteTime in order to get the most recently updated file. CreationTime gets changed when a file is copied to another disk..
Also (thanks Steven) I changed the variable names from $_varname to $varname to avoid confusion with PowerShell's $_ Automatic Variable

How to copy files using a txt list to define beginning of file names

Hello awesome community :)
I have a list containing a bunch of SKU's. All the filenames of the files, that I need to copy to a new location, starts with the corresponding SKU like so
B6BC004-022_10_300_f.jpg
In this case "B6BC004" is the SKU and my txt list contains "B6BC004" along with many other SKU's.
Somewhere in the code below I know I have to define that it should search for files beginning with the SKU's from the txt file but I have no idea how to define it.
Get-Content .\photostocopy.txt | Foreach-Object { copy-item -Path $_ -Destination "Z:\Photosdestination\"}
Thanks in advance :)
If all files start with one of the SKU's, followed by a dash like in your example, this should work:
$sourceFolder = 'ENTER THE PATH WHERE THE FILES TO COPY ARE'
$destination = 'Z:\Photosdestination'
# get an array of all SKU's
$sku = Get-Content .\photostocopy.txt | Select-Object -Unique
# loop through the list of files in the source folder and copy all that have a name beginning with one of the SKU's
Get-ChildItem -Path $sourceFolder -File -Recurse |
Where-Object { $sku -contains ($_.Name -split '\s*-')[0] } |
ForEach-Object { $_ | Copy-Item -Destination $destination }
I haven't tested this so please proceed with caution!
What is does it loops through all the items in your photostocopy.txt file, searches the $source location for a file(s) with a name like the current item from your file. It then checks if any were found before outputting something to the console and possibly moving the file(s).
$source = '#PATH_TO_SOURCE'
$destination = '#PATH_TO_DESTINATION'
$photosToCopy = Get-Content -Path '#PATH_TO_TXT_FILE'
$photosToCopy | ForEach-Object{
$filesToCopy = Get-ChildItem -Path $source -File | Where-Object {$_.Name -like "$_*"}
if ($fileToCopy.Count -le 0){
Write-Host "No files could be found for: " $_
}else{
$filesToCopy | ForEach-Object{
Write-Host "Moving: " $_.Name
Copy-Item -Path $_.FullName -Destination $destination
}
}
}
Let me know how if this helps you :)

Compare-Object Delete File if file does not exist on source

I have this PowerShell code that compares 2 directories and removes files if the files no longer exist in the source directory.
For example say I have Folder 1 & Folder 2. I want to compare Folder 1 with Folder 2, If a file doesn't exist anymore in Folder 1 it will remove it from Folder 2.
this code works ok but I have a problem where it also picks up file differences on the date/time. I only want it to pick up a difference if the file doesn't exist anymore in Folder 1.
Compare-Object $source $destination -Property Name -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | % {
if(-not $_.FullName.PSIsContainer) {
UPDATE-LOG "File: $($_.FullName) has been removed from source"
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
}
Is there an extra Where-Object {$file1 <> $file2} or something like that.?
I am not sure how you are getting the information for $source and $destination I am assuming you are using Get-ChildItem
What i would do to eliminate the issue with date/time would be to not capture it in these variables. For Example:
$source = Get-ChildItem C:\temp\Folder1 -Recurse | select -ExpandProperty FullName
$destination = Get-ChildItem C:\temp\Folder2 -Recurse | select -ExpandProperty FullName
By doing this you only get the FullName Property for each object that is a child item not the date/time.
You would need to change some of the script after doing this for it to still work.
If I am not getting it wrong, the issue is your code is deleting the file with different time-stamp as compared to source:
Did you try -ExcludeProperty?
$source = Get-ChildItem "E:\New folder" -Recurse | select -ExcludeProperty Date
The following script can serve your purpose
$Item1=Get-ChildItem 'SourcePath'
$Item2=Get-ChildItem 'DestinationPath'
$DifferenceItem=Compare-Object $Item1 $Item2
$ItemToBeDeleted=$DifferenceItem | where {$_.SideIndicator -eq "=>" }
foreach ($item in $ItemToBeDeleted)
{
$FullPath=$item.InputObject.FullName
Remove-Item $FullPath -Force
}
Try something like this
In PowerShell V5:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 -file).Name
gci $yourdir2 -file | where Name -notin $filesnamedir1| remove-item
In old PowerShell:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 | where {$_.psiscontainer -eq $false}).Name
gci $yourdir2 | where {$_.psiscontainer -eq $false -and $_.Name -notin $filesnamedir1} | remove-item
If you want to compare files in multiple dir, use the -recurse option for every gci command.

Rename if file already exist in powershell

I created ps script to copy only files in the folder structure- recursive
cp $source.Text -Recurse -Container:$false -destination $destination.Text
$dirs = gci $destination.Text -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName
$dirs | Foreach-Object { Remove-Item $_ }
it is working fine. but the problem i have files in the same names. it is not copying duplicated files. i need to rename if file already exist
source:
folderA--> xxx.txt,yyy.txt,
folderB-->xxx.txt,yyy.txt,zzz.txt,
folderc-->xxx.txt
destination (requirement)
xxx.txt
xxx1.txt
xxx2.txt
yyy.txt
yyy1.txt
zzz.txt
Here a solution where I use the Group-Object cmdlet to group all items by the filename. I then iterate over each group and if the group contains more then one file, I append _$ito it where $i starts by one and gets incremented:
$source = $source.Text
$destination = $destination.Text
Get-ChildItem $source -File -Recurse | Group-Object Name | ForEach-Object {
if ($_.Count -gt 1) { # rename duplicated files
$_.Group | ForEach-Object -Begin {$i = 1} -Process {
$newFileName = $_.Name -replace '(.*)\.(.*)', "`$1_$i.`$2"
$i++
Copy-Item -Path $_.FullName -Destination (Join-Path $destination $newFileName)
}
}
else # the filename is unique, just copy it.
{
$_.Group | Copy-Item -Destination $destination
}
}
Note:
You may change the -File to -Container:$false if your PowerShell version doesn't support it. Also note that the script doesn't look into the destination folder whether a file with the same name already exist.