How to batch copy and rename files from one folder to another? - powershell

I have 100 folders containing a psd file:
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameX\psd\logo.psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameY\psd\logo.psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameZ\psd\logo.psd
...
Each psd file contains a picture:'logo.psd'
I want to copy 'logo.psd' of 'filenameX', 'filenameY', 'filenameZ' located respectively in,
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameX\psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameY\psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\ET2013\filenameZ\psd
...
to another folder,
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\Logos\
and rename 'logo' file with 'logo_parentfoldername' this way: 'logo_filenameX','logo_filenameY', 'logo_filenameZ'.
End Result:
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\Logos\logo_filenameX.psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\Logos\logo_filenameY.psd
C:\Users\Harvey\Documents\Archive011112\TFG\SG\ET\Logos\logo_filenameZ.psd
....
Hope it's clear!

Something like this should do the trick.
You want to use Get-ChildItem with -Recurse to grab all those files within each subdirectory.
Get-ChildItem -Path $dir -Recurse
But filter your results to only those with the .psd extension.
|?{$_.Extension -eq ".psd"}
Then for each of those files get the name of the parent's parent directory.
$_.Directory.Parent.Name
And finally copy the file to our new file destination.
Copy-Item $_.FullName $copyto
So the end product looks something like this:
$dir = "C:\source\"
$destination = "C:\destination\"
Get-ChildItem -Path $dir -Recurse | ?{$_.Extension -eq ".psd"} | % {
$copyto = $destination + $_.Directory.Parent.Name + ".psd"
Copy-Item $_.FullName $copyto
}

Related

Powershell: Moving named files to their corresponding folder

enter image description hereI have a folder which has a bunch of files named: WBF123456, WBF135464, etc. These files need to be moved to the corresponding folder. At the moment I am using the commandline to manually enter the numbers of each file so they get moved, using this code:
$files = $args[0]
mv O:\SCAN\SecSur\*$files.pdf O:\SPG\G*\*\*$files
How can I automate this process?
It needs to identify the number in the filename, then move it to the folder containing the same number.
Any help would be great. Thanks.
I need to get the files on the left, inside the corresponding folders on the right.
Maybe the below solution will help you. You should change $origin_path and $destination_path
$origin_path= "C:\Users\geralexgr\Desktop\kati\files"
$destination_path = "C:\Users\geralexgr\Desktop\kati\folders"
Get-ChildItem $origin_path -Recurse -Include *.txt | ForEach-Object {
$folder = [regex]::Matches($_.Name, "\d+(?!.*\d+)").value
Move-Item $_.FullName $destination_path\$folder
}
The example will place files under the folders that match the numeric regex.
After powershell execution file WBF12 gets inside 12 folder
Apparently the files to move are .pdf files, so what you can do is get a list of those files in the source folder and then loop over that list to create (if needed) the destination subfolder and move the file there.
Try:
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# create the target path for the file
$targetFolder = Join-Path -Path $destinationRoot -ChildPath $numName
# create that subfolder if it does not already exist
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# now, move the file
$file | Move-Item -Destination $targetFolder
}
Seeing your screenshots, this might be a better approach for you.
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
# get a list of target folders for the files to be moved to and create a lookupHashtable from their names
$targets = #{}
Get-ChildItem -Path $destinationRoot -Directory | Where-Object {$_.Name -match '(\d+)'} | ForEach-Object {
$targets[$matches[1]] = $_.FullName # key is the number, value is the directory fullname
}
# get a list of files to move
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File | Where-Object {$_.Name -match '\d+'}
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# see if we have a target folder with that same number in its name
if ($targets.ContainsKey($numName)) {
$targetFolder = $targets[$numName]
Write-Host "Moving file $($file.Name) to $targetFolder"
$file | Move-Item -Destination $targetFolder
}
else {
Write-Warning "Could not find a destination folder for file $($file.Name).."
}
}

Copying Files to Another Folder While Keeping a Single Parent Directory

I'm still new to PowerShell and I'm trying to do something I haven't seen an exact answer for yet. We have one large folder with many subfolders that contain individual audio files (our phone system records and places audio files in folders by date). I want to get certain files from within those folders and move them to a different folder, but I want to create the parent folder that the files came from in the new location. I am not grabbing all files within the folders, only a few. For example:
I want to move a file at C:\CopyFrom\02182019\AudioFile.wav
I have a folder at C:\CopyTo, but I want the destination to be C:\CopyTo\02182019\AudioFile.wav
I want the script to create the folder if it doesn't exist, but copy the files into the folder if it does.
I'm currently using Get-ChildItem -Include to get the files I need and piping it into a foreach loop that I found online. This is as close as I've gotten to what I need, but it copies the ENTIRE folder structure, starting at the root, so my destination ends up being:
C:\CopyTo\CopyFrom\02182019\AudioFile.wav
Here is what I have so far:
Get-ChildItem $SourceFolder -Include $ExtArray -Recurse | forEach {
## Remove the original root folder
$split = $_.Fullname -split '\\'
$DestFile = $split[1..($split.Length - 1)] -join '\'
## Build the new destination file path
$DestFile = "C:\DestinationFolder\$DestFile"
## Copy-Item won't create the folder structure so we have to
## create a blank file and then overwrite it
$null = New-Item -Path $DestFile -Type File -Force
Copy-Item -Path $_.FullName -Destination $DestFile -Force
}
I found the foreach loop in this article. I'm assuming there is more I can add to the $split line that will allow me to shave off the rest of the directory structure, but I'm still pretty new to this and don't understand the syntax well enough.
I know this is kind of convoluted to explain, so please let me know if any clarification is needed.
Try this:
$ExtArray = "keep"
$SourceFolder = "C:\source"
$DestFolder = "C:\dest"
Get-ChildItem $SourceFolder -Recurse -Include "*keep*" | foreach {
$source_dir = $_.DirectoryName
$dest_dir = $_.DirectoryName.replace($SourceFolder, $DestFolder)
if (Test-Path $dest_dir) {
Copy-Item -Path $_ -Destination $dest_dir -Recurse
} else {
New-Item -Path $dest_dir -ItemType "directory" | out-null
Copy-Item -Path $_ -Destination $dest_dir -Recurse
}
}
Here's my attempt at this - I set the top level directory as one variable and the underlying folder structure as another.
$File = "C:\test\IT\testfile.docx"
$Destination = "C:\test2\"
$test2 = "\IT\"
mkdir "$Destination\$test2"
Copy-Item -Path $File -Destination "$Destination\$test2" -recurse
I'm not sure how to implement this into your current code but hopefully it gets the wheels spinning and sends you in the right direction!

Search folder for filename and copy item to another location

Hello in our environment we have the following structure:
\\server\share1\Subfolder1\Subfolder3\123456.jpg
\\server\share1\Subfolder2\Subfolder4\456789.jpg
\\server\share2\123456.tif
\\server\share2\456789.tif
What I want to do is the following: Check if the item exists in share2 as tif. If so then I want to copy the tif file to the same location as the jpg (share1).
Via Get-ChildItem -Recurse -File I can get all the files, but I don't know how to compare the filename to share2 and copy the tif file to the same location as the jpg.
Thanks in advance!
This should do what you need:
$JpgFiles = Get-ChildItem .\Share1 -Recurse -File -Filter *.jpg
ForEach ($File in $JpgFiles) {
$TifFile = Get-ChildItem .\Share2 -Recurse -File -Filter *.tif | Where { $_.BaseName -eq $File.BaseName }
If ($TifFile) { Copy-Item -Path $TifFile.FullName -Destination $File.DirectoryName }
}
Gets all the .jpg files in Share1
Iterates through each file and compares the .basename property to the files in Share2 (basename is the file name without the extension).
If it returns a file, copies that file to share1

Move File to new location where Parent Folder Name Matches

Problem
I am working on a rollback feature in my application in which I copy the files from a backup/rollback directory to a destination folder. As simple as that sounds, this is where it gets complicated. Due to all the files sharing the same or similar name, I used the parent folder as the anchor to help enforce unique locations.
I want to essentially recursively search a directory and wherever a folder name matches a parent directory of an object, paste a copy of the object into that folder, overwriting whatever file(s) share a name with said object.
A more visible way to represent this would be:
$Path = C:\Temp\MyBackups\Backup_03-14-2017
$destination = C:\SomeDirectory\Subfolder
$backups = GCI -Path "$Path\*.config" -Recursive
foreach ($backup in $backups) {
Copy-Item -Path $backup -Destination $destination | Where-Object {
((Get-Item $backup).Directory.Name) -match "$destination\*"
}
}
However, the above doesn't work and none of my research is finding anything remotely similar to what I'm trying to do.
Question
Does anyone know how to Copy an Item from one location to another in which the parent folder of the copied item matches a folder in the destination using PowerShell?
Enumerate the backed-up files, replace the source base path with the destination base path, then move the files. If you only want to replace existing files, test if the destination exists:
Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
$dst = $_.FullName.Replace($Path, $destination)
if (Test-Path -LiteralPath $dst) {
Copy-Item -Path $_.FullName -Destination $dst -Force
}
}
If you want to restore files that are missing in the destination make sure to create missing directories first:
Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
$dst = $_.FullName.Replace($Path, $destination)
$dir = [IO.Path]::GetDirectoryName($dst)
if (-not (Test-Path -LiteralPath $dir -PathType Container)) {
New-Item -Type Directory -Path $dir | Out-Null
}
Copy-Item -Path $_.FullName -Destination $dst -Force
}
You may be over thinking this. If you are backing up a web.config file from a website, I'd highly advise using the SiteID as the backup folder. Then simply utilize this as the means to find the right folder to copy the web.config file to when you want to rollback.
Ideally when working with any group of items (in this instance websites) try to find a unique identifier for the items. SiteIDs are ideal for this.
$Path = C:\Temp\MyBackups\Backup_03-14-2017 #In this directory store the web.config's in directories that match the SiteID of the site they belong to
#For example, if the site id was 5, then the full backup directory would be: C:\Temp\MyBackups\Backup_03-14-2017\5
$backups = Get-ChildItem -Path $Path -Include *.config -Recurse
foreach ($backup in $backups)
{
$backupId = $backup.Directory.Name
$destination = (Get-Website | where {$_.id -eq $backupId}).physicalPath
Copy-Item -Path $backup -Destination $destination
}

Powershell file copy and rename based on path

I have folder Main that has many subfolders (AA,AB,AC,...,ZZ), every subfolder has 5 folders (1,2,3,4,5) in which one them can have .csv file.
I need a to write a script that would copy every .csv file into output folder and rename it based on in which subfolder it was found (AA.csv, BB.csv and so on) all I managed to do was get a list of csv files and create output folder.
New-Item C:\Output -force
$FileExtension = ".csv"
$Dir = get-childitem $FolderPath -recurse
$List = $Dir | where {$_.extension -eq $FileExtension}
$List | format-table Name
I suppose you can have multiple csv files into your dirs, i propose this solution
$Pathsource="C:\Temp\" # let the '\'
$Pathdestination="C:\Temp2\"
#remove -whatif if its ok
Get-ChildItem $Pathsource -Recurse -Filter "*.csv" | %{Copy-Item $_.FullName ($Pathdestination + $_.FullName.Replace($Pathsource , '').Replace('\', '_')) -WhatIf}