Powershell Flatten dir recursively - powershell

Found a couple of semi-related links:
How to merge / 'flatten' a folder structure using PowerShell - recursive
but my ask is that I have a root dir P:/files
which has several layers of sub directories etc I'd like to flatten all of them so that all the -Files are moved just to the root of P:/files
I don't need to be concerned with duplicates as I'll make sure there are non well before this stage.
it looks like I can use powershell to get a list of all the files no matter the level, and then just for-each over them and a move?
Get-ChildItem -LiteralPath P:\files -Directory | Get-ChildItem -Recurse -File
help on the loop?

A single recursive Get-ChildItem that pipes to Move-Item should do:
Get-ChildItem -File -Recurse -LiteralPath P:\files |
Move-Item -Destination $yourDestination -WhatIf
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
If you need to exclude files directly located in P:\files:
Get-ChildItem -Directory -Recurse -LiteralPath P:\files | Get-ChildItem -File |
Move-Item -Destination $yourDestination -WhatIf
Note the use of -Directory and -Recurse first, so that all subdirectories in the entire subtree are returned, followed by a non-recursive Get-ChildItem -File call that gets each subdirectory's immediate files only.

Related

How can I delete specific files in a folder but not the sub folders?

I have a huge folder structure and I want to delete some specific files only from main folders and leave sub folders intact.
Example:
Folder A/Sub-folderB/
Now , I want to delete files from Folder A ONLY , and this should continue until the last folder N.
This is the code i have tried ,
Get-Childitem C:\serverfolders\users\* | Where-Object {-Not $_.PSIsContainer} | Foreach-Object {Remove-Item $_.FullName}
Any help would be greatly appreciated.
Just add "-File" option :)
Get-Childitem C:\serverfolders\users -File | Remove-Item -force
You can read more on Get-ChildItem help on MS
You can use the -Depth parameter of Get-ChildItem to limit the number of subdirectory levels to include in the recursion. In your case, you only want 1 level deep in order to leave any subfolders intact.
Get-ChildItem -Path 'C:\serverfolders\users' -Depth 1 -File -Recurse | Remove-Item -WhatIf
You say you want to delete some specific files only, and for that you can use the -Include parameter of
Get-ChildItem like this:
Get-ChildItem -Path 'C:\serverfolders\users' -Depth 1 -File -Recurse -Include '*.txt', '*.pdf', '*.doc*' | Remove-Item -WhatIf
When satisfied with the results on screen, remove the -WhatIf switch

Move Files from one folder to another without using -Recurse

I have a powershell script where all I want to do is move files of a certain type from the folder specified to a destination folder. Unfortunately this doesn't work without -Recurse contained which is not the functionality I want to achieve. If I include -Recurse it starts to move images from "D:/Photos/x/" etc. All i want to do is move files from "D:/Photos" to the destination
Get-ChildItem "D:\Photos" -Include *.png, *.jpeg, *.jpg |
Move-Item -Destination "D:\Photos\Powershell Task" -Force
The -Include parameter without -Recurse does not work.
However, there is another way to have the -Include do what you want (namely filter on more than one extension) and that is to add \* to the Path.
In your case:
Get-ChildItem -Path "D:\Photos\*" -Include *.png, *.jpeg, *.jpg |
Move-Item -Destination "D:\Photos\Powershell Task" -Force
Mind you: The destination path D:\Photos\Powershell Task needs to exist.
Solution :
Get-ChildItem "D:\Photos\*" -Include *.png, *.jpeg, *.jpg | Move-Item -Destination "D:\Photos\Powershell Task" -Force
Explanation :
When selecting Get-ChildItem to use include you must have -recursion selected OR define what the include is represented using wildcards in the -path.
This case D:\Photos\* is defining to get all children in D:\Photos that have both a name and extension then you are filtering those by using -include to say only the ones with extensions .jpg .png

Using Remove-Item cmdlet but excluding sub-directory

I want to remove the following files from the source, however in the source there is a sub-directory that contains files with similar names. When I run the following command it is deleting files in the sub-directory with similar file name. Is there a way to just delete the files from the source and not the sub-directory?
Example: test_1_file, test_2_file, test_3_file exists in each directory, TestFolder and TestFolder/sub
$source = testfolder
remove-item -Path $source -filter test_*_file -recurse -force
It's usually easiest to pipe the output of Get-ChildItem cmdlet into Remove-Item. You then can use the better filtering of Get-ChildItem as I think -Recurse in Remove-Item has some issues. You can even use Where-Object to further filter before passing to Remove-Item
$source = testfolder
Get-ChildItem -Path $source -Filter test_*_file -Recurse |
Where-Object {$_.Fullname -notlike "$source\sub\*"} |
Remove-Item -Force
If the files to delete:
are all located directly in $source
and no other files / directories must be deleted:
Remove-Item -Path $source/test_*_file -Force
No need for -Recurse (as #Bill_Stewart notes).
Note: For conceptual clarity I've appended the wildcard pattern (test_*_file) directly to the $source path.
Using a wildcard expression separately with -Filter is generally faster (probably won't matter here), but it has its quirks and pitfalls.

How to use the Copy-Item cmdlet correctly to copy piped files

I am building a small script which should copy all .zip files to a special folder called F:\tempzip.
I tried it with Copy-Item cmdlet, but I didn't manage to do it. The script should copy all files from this folder (recursively) which are ".zip".
This is the part of the script I am talking about:
get-childitem F:\Work\xxx\xxx\xxx -recurse `
| where {$_.extension -eq ".zip"} `
| copy-item F:\tempzip
What do I have to add?
It's a lot simpler than that. Copy-Item has its own -Recurse switch. All you have to do is:
Copy-Item F:\Work\xxx\xxx\xxx\*.zip F:\tempzip -Recurse
When piping items to copy-item you need to tell it that "F:\tempzip" is the destination path.
| Copy-Item -Destination F:\tempzip
You can also cutout piping to the where operator by using Get-ChildItem's parameter -filter.
Get-Childitem "C:\imscript" -recurse -filter "*.zip" | Copy-Item -Destination "F:\tempzip"
Edit: Removal of unnecessary foreach loop and updated explanation.
For whatever reason, the Copy-Item recursion didn't accomplish what I wanted, as mentioned here, and how it is documented to work. If you have a bunch of *.zip or *.jpg files in arbitrarily deep subfolder hierarchies, and you want to copy them to a single place (one flat folder, elsewhere), I had better luck with a piped command involving Get-ChildItem. Say you are currently in the folder containing the root of your search:
Get-ChildItem -Recurse -Include *.zip | Copy-Item -Destination C:\Someplace\Else
That command will copy all the files and not duplicate the folder hierarchies.

Copy-Item / Remove-Item child-content only without root folder?

Hi I'm struggling mightily with the following - suppose I have the following directory structure C:\Temp\Test1 and C:\Temp\Test2
What I'd like to do is recursively copy the child-contents of C:\Temp\Test1 to C:\Temp\Test2 without copying the actual folder C:\Temp\Test1 ..right now if I use the command
Copy-Item C:\Temp\Test1 C:\Temp\Test2 -Recurse
Will result in C:\Temp\Test2\Test1 and no combination of parameters seems to alleviate the problem
Similarly, when I wish to remove all the child content in C:\Temp\Test2 I wish to only delete the child content and not the actual folder eg
Remove-Item C:\Temp\Test2\ -Recurse
Is removing the \Test2 folder. I've tried so many variations of parameters - how can I accomplish what I am trying to do?
Take a look at the get-childitem command. You can use this in the pipeline to copy or remove all items underneath the root folders:
# recursively copy everything under C:\Temp\Test1 to C:\Temp\Test2
get-childitem "C:\Temp\Test1" | % {
copy-item $_.FullName -destination "C:\Temp\Test2\$_" -recurse
}
# recursively remove everything under C:\Temp\Test1
get-childitem "C:\Temp\Test1" -recurse | % {
remove-item $_.FullName -recurse
}
Copy-Item C:\Temp\Test1\* C:\Temp\Test2
Remove-Item "C:\Temp\Test2\*" -recurse
Works too :)