Powershell - copy files to different destination folders based on file names - powershell

Dear Powershell Gurus,
I have a few thousands of files in a folder called C:\Downloads\Signs.
The files are named with their dimensions such as 13X20 abcdjd.psf, 8X20 jdscnjfc.psf, 14X24 dje.psf etc.
What I want to do is to move these files to destination folders created within the C:\Downloads\Signs and the folder names are the dimensions of the file names. Example the folder names will be 13X20, 8X20, 14X24 etc and it depends upon as many unique file names with their dimensions.
So, instead of moving them manually looking at how many files are there in the C:\Downloads\Signs folder and then moving them individually, how can we do it in Powershell?
Thanks,
Sanders.

This script will pick up all psf from the root of the C:\Downloads\Signs folder and will move the files to the destination folders (folders will create if they do not exist):
Get-ChildItem C:\Downloads\Signs -Filter *.psf | Where-Object {!$_.PSIsContainer} | Foreach-Object{
$dest = Join-Path $_.DirectoryName $_.BaseName.Split()[0]
if(!(Test-Path -Path $dest -PathType Container))
{
$null = md $dest
}
$_ | Move-Item -Destination $dest -Force
}

Related

File System Searches and Files Moves with Powershell

I have a bit of a random task I have created for myself. I basically have a git repo in which there is a file structure and within a specific folder, I have several subfolders and nested in those folders are 3 config folders which have the same name. I am trying to create a powershell script thatll comb through the "Target Folder", copy the "Folder 1", "Folder 2", and "Folder 3", but only copy the contents of the 3 "Config Folder"s, maintaining that file structure, but only copying whats needed. Ideally, after that process, id love to rename these files with part of the name of the folder name to help differentiate. I do have plans to integrate a second part of the script to parse through those config files and export to an excel doc, but not sure how much I need that at the moment. The intended output is below, played around with a few misc file structure commands, but have not found much to help me achieve the below result.
File Structure:
Repo
TARGET FOLDER
DATA
FOLDER1
CONFIGFOLDER
MISC
FOLDER2
CONFIGFOLDER
MISC
FOLDER3
CONFIGFOLDER
ETC
Hoping to end up with
Export Folder
TARGET FOLDER
FOLDER1
CONFIGFOLDER
List of files with "FOLDER1_ogfilename.yaml"
FOLDER2
CONFIGFOLDER
List of files with "FOLDER2_ogfilename.yaml"
FOLDER3
CONFIGFOLDER
List of files with "FOLDER3_ogfilename.yaml"
I have created the following item to attempt this, and it copies the file structure, but it creates a folder for each .yaml file within that folder.
$sourceDir = "C:\Users\hhh\appdev\hhh\data\environments"
$targetDir = "C:\Users\hhh\appdev\targetfolder"
Get-ChildItem $sourceDir -Recurse | % {
$dest = $targetDir + $_.FullName.SubString($sourceDir.Length)
If (!($dest.Contains('research,qa,production,global')) -and !(Test-Path $dest))
{
mkdir $dest
}
Copy-Item $_.FullName -Destination $dest -Force
}
There are issues with your code.
you need to add switch -File to the Get-ChildItem cmdlet to have it look for files, not the directories inside $sourceDir
use Join-Path to construct your destination folder path. By adding the two strings together like you do, you will be missing a backslash
use the files DirectoryName property instead of its FullName when taking the substring from it, otherwise the $dest variable will also include the file name (creating folders for every file)
apparently you wish to not copy files from folders having certain keywords in their path name, so you need to put the copy command inside the test, not below it
Try:
$sourceDir = "C:\Users\hhh\appdev\hhh\data\environments"
$targetDir = "C:\Users\hhh\appdev\targetfolder"
Get-ChildItem $sourceDir -File -Recurse | ForEach-Object {
# use the files DirectoryName, not the FullName property, otherwise the path will include the file name as well
$dest = Join-Path -Path $targetDir -ChildPath $_.DirectoryName.SubString($sourceDir.Length)
# exclude paths containing these words
if ($dest -notmatch 'research|qa|production|global') {
# create the new folder if it does not already exist
$null = New-Item -Path $dest -ItemType Directory -Force
$_ | Copy-Item -Destination $dest -Force
}
}

Copy-Item with overwrite?

Here is a section of code from a larger script. The goal is to recurse through a source directory, then copy all the files it finds into a destination directory, sorted into subdirectories by file extension. It works great the first time I run it. If I run it again, instead of overwriting existing files, it fails with this error on each file that already exists in the destination:
Copy-Item : Cannot overwrite the item with itself
I try, whenever possible, to write scripts that are idempotent but I havn't been able to figure this one out. I would prefer not to add a timestamp to the destination file's name; I'd hate to end up with thirty versions of the exact same file. Is there a way to do this without extra logic to check for a file's existance and delete it if it's already there?
## Parameters for source and destination directories.
$Source = "C:\Temp"
$Destination = "C:\Temp\Sorted"
# Build list of files to sort.
$Files = Get-ChildItem -Path $Source -Recurse | Where-Object { !$_.PSIsContainer }
# Copy the files in the list to destination folder, sorted in subfolders by extension.
foreach ($File in $Files) {
$Extension = $File.Extension.Replace(".","")
$ExtDestDir = "$Destination\$Extension"
# Check to see if the folder exists, if not create it
$Exists = Test-Path $ExtDestDir
if (!$Exists) {
# Create the directory because it doesn't exist
New-Item -Path $ExtDestDir -ItemType "Directory" | Out-Null
}
# Copy the file
Write-Host "Copying $File to $ExtDestDir"
Copy-Item -Path $File.FullName -Destination $ExtDestDir -Force
}
$Source = "C:\Temp"
$Destination = "C:\Temp\Sorted"
You are trying to copy files from a source directory to a sub directory of that source directory. The first time it works because that directory is empty. The second time it doesn't because you are enumerating files of that sub directory too and thus attempt to copy files over themselves.
If you really need to copy the files into a sub directory of the source directory, you have to exclude the destination directory from enumeration like this:
$Files = Get-ChildItem -Path $Source -Directory |
Where-Object { $_.FullName -ne $Destination } |
Get-ChildItem -File -Recurse
Using a second Get-ChildItem call at the beginning, which only enumerates first-level directories, is much faster than filtering the output of the Get-ChildItem -Recurse call, which would needlessly process each file of the destination directory.

Copy files from one folder to many via Powershell

I need to copy the files from one folder to many. Here's an example of my directory structure:
\\files\CA1\Files\Files
CA = state code
1 = office in that state
I want to copy all files from a source folder into the last files folder. The last files folder in that directory structure above is the destination. The script just needs to cycle through all of the directories with that state code and copy the new files into \\files\CA*\files\FILES\ folder. For instance, I want to copy all files from c:\documents into all folders that are for CA, regardless of the office number. Here's what I have so far:
$source = 'C:\Documents'
$destination = (Get-ChildItem -Path \\files\CA*\Files\Files -Recurse -Directory)
foreach ($dir in $destination){
Get-ChildItem $dir.Fullname | ForEach-Object {
$_.FullName
#Copy-Item -Path $Source -Destination $_ -Force -Recurse -WhatIf
}}

Powershell complex copy and create directories containing name of parent

I have a complex folder structure to move
I have a folder containing 2000 files that must be moved in new file structure, I do some simple task with powershell but not so complex so I'm completely lost... Didn't found any solution on other questions...
all folders containing 23 files (some .dds some .xml and so ones) folder must be moved completely
here is the actual situation:
files\128891\
files\128986\
files\129362\
files...\
that must be moved to:
files\128891\aaa\bbb\ccc\ddd\eee\real\128891\
files\128986\aaa\bbb\ccc\ddd\eee\real\128986\
files\129362\aaa\bbb\ccc\ddd\eee\real\129362\
files...\aaa\bbb\ccc\ddd\eee\real...\
have around 2000 folders in files that must be moved with their files in
Thanks a lot for helping
You can modify my code (not better way but works)
$foldernames=Get-ChildItem -Recurse "D:\testdir" | ?{ $_.PSIsContainer } #get all folder in start folder, for you must be "...files\"
foreach($foldername in $foldernames){
$files=Get-ChildItem -Path $foldername.FullName|Where-Object {! $_.PSIsContainer} #get all files in current folder, no recurse,no subfolders.
$files|Move-Item -Destination (New-Item -ItemType Directory -Path (Join-Path -path $foldername.FullName -ChildPath ("aaa\bbb\ccc\ddd\eee\real\"+$foldername.Name)) -Force)
#move all files and create directories
}
Additional:
If you have in folder , subfolders you must fix code like that
$foldernames=Get-ChildItem "D:\testdir" | ?{ $_.PSIsContainer }
foreach($foldername in $foldernames){
$files=Get-ChildItem -Path $foldername.FullName
$files|Move-Item -Destination (New-Item -ItemType Directory -Path (Join-Path -path $foldername.FullName -ChildPath ("aaa\bbb\ccc\ddd\eee\real\"+$foldername.Name)) -Force)
}
It's move all from folder 128891(an exapmle) including subfolders
If you have in folder subfolders but you want move only files from it you must filetring like this:
$files=Get-ChildItem -Path $foldername.FullName -recurse|Where-Object {! $_.PSIsContainer}
But remember in this case errors may occur due to duplicate file names

Copying Folders with Wildcards

I am trying to copy a whole bunch of files using Powershell, from one directory to another on my computer.
I used Get-ChildItem C:\Users\Tom\Google Drive\My Files\*\Assessment 1\* to identify that this was the path that I wanted to copy too, and I know about Copy-Item, but I want to maintain parts of the path name when copied.
Example:
If I copy from C:\Users\Tom\Google Drive\My Files\Cool Stuff\Assessment 1\*
I want the files to go to a folder that is created called C:\Users\Tom\Archive\Cool Stuff\Assessment 1
Whereas if I copy from C:\Users\Tom\Google Drive\My Files\New Stuff\Assessment 1\*
I want the files to go to a folder that is created called C:\Users\Tom\Archive\New Stuff\Assessment 1
You could use the Get-ChildItem cmdlet to recursively find all Assessment 1 folders within your base directory and then remove the base path using -replace to finally copy the items using the Copy-Item cmdlet:
$baseDir = 'C:\Users\Tom\Google Drive\My Files\'
$destination = 'C:\Users\Tom\Archive\'
Get-ChildItem $baseDir -directory -Filter 'Assessment 1' -Recurse | ForEach-Object {
$newPath = Join-Path $destination ($_.FullName -replace [regex]::Escape($baseDir))
Copy-Item $_.FullName $newPath -Force -Recurse
}