Move Files from one folder to another without using -Recurse - powershell

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

Related

Powershell Flatten dir recursively

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.

Powershell copy file/folder based on keyword

I want to copy folder which match with the keyword. however i want powershell read the keyword from starting point. i added my script below
if any folder name contain test at the start, script will copy the folder. but it's coping all folder even if "Test" keyword is available in the middle name. like if there is two folder
"This.is.a.Test.Folder"
"Test.this.is.a.Folder"
I want powershell copy only "Test.this.is.a.Folder"
any help please
$dest = "D:\2";
$include= #("*Test*")
Get-ChildItem $source -recurse -Force -Verbose -include $include | copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}```
Your wildcard is meant to capture anything that contains the word Test in this case.
If you want to specifically start with the word Test followed by anything: Test*
Contrary, anything that ends with the word Test would be: *Test
$include = #( "Test*" )
Get-ChildItem $source -Include $include -Recurse -Force -Verbose |
Copy-Item -Destination {
Join-Path $dest -ChildPath $_.FullName.Substring($source.length)
}
Note, that you can use -File to filter only files and -Directory to filter only folders.

Powershell script to copy folder structure and specific file types

I have the following script to copy the folder structure (including empty folders) and specific file types into another directory. However, the issue is that the script copies all files instead of just the .dat and .py files even though I'm using the -Include switch. How to fix this so that it only copies the desired file types
$sourceDir = "C:\User\001"
$targetDir = "C:\User\002"
Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Include '*.dat', '*.py' -Container
As #Lee_Dailey pointed out, it's probably best to use robocopy for this:
robocopy $sourceDir $targetDir *.dat *.py /e
Yes, this is tricky. You should look up the documentation for the -Include parameter
The Include parameter is effective only when the command includes the contents of an item, such as C:\Windows*, where the wildcard character specifies the contents of the C:\Windows directory.
You could make it work like this:
Copy-Item $sourceDir\* -Destination $targetDir -Recurse -Include '*.dat', '*.py'
-Container is true by default, so you can safely omit it.
Note that you can always use the -WhatIf switch to check if you command will actually do what you want.
You could make it work like this:
i use -Filter
Specifies a filter to qualify the Path parameter. The FileSystem
provider is the only installed PowerShell provider that supports the
use of filters. You can find the syntax for the FileSystem filter
language in about_Wildcards. Filters are more efficient than other
parameters, because the provider applies them when the cmdlet gets the
objects rather than having PowerShell filter the objects after they're
retrieved.
#('*.dat', '*.py') | %{Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter $_ -Force}
or
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter '*.dat' -Force
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter '*.py' -Force
it should work but
The Include parameter is effective only when the command includes the
contents of an item, such as C:\Windows*, where the wildcard character
specifies the contents of the C:\Windows directory.
Copy-Item -Destination $targetDir -Recurse -Include '*.dat', '*.py'
may find it easier to include files that can be excluded
Copy-Item -Destination $targetDir -Recurse -Exclude'*.da1', '*.xxx

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.