PowerShell to move subitems of multiple folders into their own subfolders - powershell

I'm working on a project cleaning up a file server's folder redirection folders. Would like to ask for some help with a PS script that would move the files in user folders into new "Documents" sub-folders, as we're facing manually performing this for a lot of profiles.
A tree example currently looks like:
―FolderRedirection
―――JContoso
――――――File.docx
――――――File.pptx
―――MDerby
――――――File.docx
――――――File.pptx
I'd like to be able to achieve:
―FolderRedirection
―――JContoso
――――――Documents
―――――――――File.docx
―――――――――File.pptx
―――MDerby
――――――Documents
―――――――――File.docx
―――――――――File.pptx

This should work, bear in mind for future questions you should provide at least a minimal attempt at solving the problem.
The inline comments should help you with the code logic.
# get all folders in `FolderRedirection`
foreach($dir in Get-ChildItem .\FolderRedirection -Directory) {
# create a new `Documents` folder in each sub folder
$dest = $dir | Join-Path -ChildPath Documents
$dest = New-Item $dest -ItemType Directory -Force
# get all files in each folder and move them to the new folder
$dir | Get-ChildItem -File | Move-Item -Destination $dest
}

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

Need assistance copying task

I have .dll and .sys files under folder xyz
xyz
'QcXhciFilter8086\QcXhciFilter8086.sys'
'qSarMgr8086\qSarMgr.dll'
'qcwlan_wpextwapi8086\WapiIhvExt.dll'
These need to be copied something like this under new folder
new
'QcXhciFilter8086\QcXhciFilter8086.sys'
'qSarMgr8086\qSarMgr.dll'
'qcwlan_wpextwapi8086\WapiIhvExt.dll'
What i have tried:
'Copy-Item -Path $file_path\..\*sys -Destination C:\Users\Path\new\'
Here '$file_path = \xyz\QcXhciFilter8086\QcXhciFilter8086.sys'
Result: Only .sys.dll files getting copied directly under "new" folder. However i want them under the driver name. Something like this 'new\QcXhciFilter8086\QcXhciFilter8086.sys'
Okay, I think I understand what you are asking for...
You have a folder structure like this:
[xyz]
QcXhciFilter8086
QcXhciFilter8086.sys
qSarMgr8086
qSarMgr.dll
qcwlan_wpextwapi8086
WapiIhvExt.dll
And you want this copying to another folder. Using this will copy the folder structure and files from the xyz folder to the new folder. This will copy everything, however. If you only want to copy the files that are only .sys and .dll then you will need to add another Get-ChildItem in the existing ForeEach-Object loop to look at the current directory.
Here is my proposed solution:
$source = "c:\path\to\xyz"
$destination = "c:\path\to\new"
Get-ChildItem -Path $source -Directory | ForEach-Object{
Copy-Item $_.FullName -Destination $destination -Recurse -Container
}