Powershell Recursive Copy Except Files found in Exclusion directory - powershell

Hi I have a folder Called "A" and folder "A" has files and sub folders within it. I also have another folder directory called "Exclusion" with some copied files and folders from "A" within it. I'm looking for a Powershell script or Command Line option that will COPY & MOVE all the objects from A that are NOT found in the Exclusion directory to a new folder directory called "Output".
Thanks,
-B

Use Get-ChildItem to get a list of files in your exclusion directory, then take only the names of the files and hold those in an array.
Optionally use New-Item with the -Force parameter to ensure that your output directory exists before sending files there.
Next use Get-ChildItem to iterate through all files in our source (A) directory, use Where-Object and the -notin operator to exclude any files which have the same names as those gathered from your exclusion directory, then use Move-Item to move the files to your destination (Output) directory.
[string[]]$filenamesToExclude = Get-ChildItem -Path 'c:\somewhere\exclusion' -Recurse | Select-Object -ExpandProperty Name
New-Item -Path 'c:\somewhere\output\' -ItemType 'Directory' -Force | Out-Null #ensure the target directory exists / don't output this command's return value to the pipeline
Get-ChildItem -Path 'c:\somewhere\A' -Recurse | Where-Object {$_.Name -notin $filenamesToExclude} | Move-Item -Destination 'c:\somewhere\output\'

Related

Powershell: Find Folders and Run Command in Those Folders

so trying to find a way to combine a couple of things the Stack Overflow crowd has helped me do in the past. So I know how to find folders with a specific name and move them where I want them to go:
$source_regex = [regex]::escape($sourceDir)
(gci $sourceDir -recurse | where {-not ($_.psiscontainer)} | select -expand fullname) -match "\\$search\\" |
foreach {
$file_dest = ($_ | split-path -parent) -replace $source_regex,$targetDir
if (-not (test-path $file_dest)){mkdir $file_dest}
move-item $_ -Destination $file_dest -force -verbose
}
And I also know how to find and delete files of a specific file extension within a preset directory:
Get-ChildItem $source -Include $searchfile -Recurse -Force | foreach{ "Removing file $($_.FullName)"; Remove-Item -force -recurse $_}
What I'm trying to do now is combine the two. Basically, I'm looking for a way to tell Powershell:
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
What I'm trying to do is create a script I can use to clean up an archive drive when and if space starts to get tight. The idea is that as I develop things, a lot of times I go through a ton of incremental non-final drafts (hence folder name "Draft Materials"), and I want to get rid of the exported products (the PDFs, the BMPs, the AVIs, the MOVs, atc.) and just leave the master files that created them (the INDDs, the PRPROJs, the AEPs, etc.) so I can reconstruct them down the line if I ever need to. I can tell the script what drive and folder to search (and I'd assign that to a variable since the backup location may change and I'd like to just change it once), but I need help with the rest.
I'm stuck because I'm not quite sure how to combine the two pieces of code that I have to get Powershell to do this.
If what you want is to
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
then you could do something like:
$rootPath = 'X:\Path\To\Start\Searching\From' # the starting point for the search
$searchFolder = 'Draft Materials' # the folder name to search for
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV' # an array of file patterns to delete
# get a list of all folders called 'Draft Materials'
Get-ChildItem -Path $rootPath -Directory -Filter $searchFolder -Recurse | ForEach-Object {
# inside each of these folders, get the files you want to delete and remove them
Get-ChildItem -Path $_.FullName -File -Recurse -Include $deleteThese |
Remove-Item -WhatIf
}
Or use Get-ChildItem only once, having it search for files. Then test if their fullnames contain the folder called 'Draft Materials'
$rootPath = 'X:\Path\To\Start\Searching\From'
$searchFolder = 'Draft Materials'
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV'
# get a list of all files with extensions from the $deleteThese array
Get-ChildItem -Path $rootPath -File -Recurse -Include $deleteThese |
# if in their full path names the folder 'Draft Materials' is present, delete them
Where-Object { $_.FullName -match "\\$searchFolder\\" } |
Remove-Item -WhatIf
In both cases I have added safety switch -WhatIf so when you run this, nothing gets deleted and in the console is written what would happen.
If that info shows the correct files are being removed, take off (or comment out) -Whatif and run the code again.

Copying all Files in Subdirectories to a Single Folder with Robocopy Updating Capabilities

I am trying to copy all the files in a directory that contains many subfolders into a single separate folder. When the code is run again, rather than replacing each file in the destination folder, it should skip files that have the same timestamp and only replace those that are older.
I have used robocopy to skip the copying of files that are of the current version/older in the destination folder. However, robocopy only copies the entire directory along with its folder structure so I am unable to obtain the desired folder with a list of all the files from the source.
I have also used get child-item and then copy-item. However, although this is able to get rid of the folder structure, it overwrites each file for each iteration and is thus time-consuming.
So what I want is to combine the capabilities of robocopy and copy-item. Note that there are no specific pattern to the files that I am to copy. It is simply to COPY each file in the subdirectories that are EITHER of a NEWER version or NON-existing into a single folder.
#For copying and ease of updating destination folder
robocopy /purge /np /S /xo 'source' 'destination'
#To copy items into the destination folder without keeping folder structure
Get-ChildItem -Path 'source' -Recurse -File | Copy-Item -Destination 'destination'
Was unable to combine both, So I am stuck with using the 'copy-item' code, which is quite time consuming when copying/updating large amounts of files.
The purpose of robocopy is to preserve the folder structure. If you want to mangle subfolders robocopy is not the right tool. Use the Get-ChildItem approach, group the results by file name, sort each group by date, pick the most recent file from each group, and copy it if the corresponding destination file either doesn't exist or is older.
Something like this should do what you want:
Get-ChildItem -Path 'C:\source' -Recurse -File |
Group-Object Name |
ForEach-Object {
$src = $_.Group | Sort-Object | Select-Object -Last 1
$dst = Join-Path 'C:\destination' $src.Name
if (-not (Test-Path $dst) -or ($src.LastWriteTime -gt (Get-Item $dst).LastWriteTime)) {
$src | Copy-Item -Destination $dst
}
}

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
}

Use PowerShell to copy all files in many folders to a single folder

Copy-Item -Path D:\DB-DNLD\ -Filter *.csv -Destination D:\Dump\CSV -Recurse
I used this command, but it copied all .csv files along with existing folder structures, but my intention is just to copy all CSV to new single destination folder excluding source folder structures.
The Copy-Item cmdlet will maintain the tree structure. If you want to flatten the structure, you can locate the items with Get-ChildItem cmdlet then pipe that to a loop where each file it copied to the destinition folder individually.
dir -Path D:\DB-DNLD\ -Filter *.csv -Recurse | ForEach-Object { Copy-Item $_.FullName D:\Dump\CSV }

Copy and Raname File in Powershell

I want to copy file
base.txt
To Other Folders And I want his name change To The Folder Name.
cd c:\Program\Levels
copy-item *.txt c:\Books -force -recurse
Get-ChildItem C:\Books -Filter *.txt -Recurse | Rename-Item -NewName { $_.Directory.Name}
So he's copying *.txt for the folder 'Books' and renaming the file to 'books.txt' but, he did not copy the file to subfolders within 'Books'
I want it to copy the .txt for subfolders in 'Books' and rename the .txt to the folder name.
Obs: the .txt file is unique
So the file base.txt which is presumably some sort of template will be copied to each subfolder in C:\Books? I think I can understand your logic approach but I offer this as a solution instead.
$templateFile = "C:\temp\base.txt"
Get-ChildItem "C:\Books" | Where-Object {$_.PSIsContainer} |ForEach-Object{
$newName = "{0}\{1}.txt" -f $_.FullName, $_.Name
Copy-Item -Path $templateFile -Destination $newName
}
Gather each subdirectory of "C:\Books" and in each of those directories copy the file base.txt to its new location where its name is the name of the parent folder.