If i want to copy content from a directory without subdirectorys to a NEW folder the Documentations says unter Example 3:
If the Path includes *, all the directory's file contents, without the subdirectory trees, are copied to the new destination directory. For example:
Copy-Item -Path "C:\Logfiles*" -Destination "C:\Drawings\Logs" -Recurse
But this only works if under Path ("C:\Logfiles") are subdirectorys.
C:\Logfiles exists and contains only files
C:\Drawings exists
Copy-Item -Path "C:\Logfiles\*" -Destination "C:\Drawings\Logs" -Recurse
Directory "Logs" is created under "C:\Drawings" with all Files from "C:\Logfiles"
Powershell copy one File from Path ("C:\Logfiles") to "C:\Drawings" and name it "Logs"
All other Files are ignored
If you create inside C:\logfiles a directory everything works as it should.
Powershell 7.0.1
I agree that the behavior is counter-intuitive.
What happens is that if the -Destination argument is a path that _doesn't yet exist_, it is interpreted as a _file_, and it is the _last_ of the input files that ends up in that file.
The workaround is to make sure that the target path exists _as a directory_ beforehand.
You can mitigate the problem somewhat if you append a \ or / to the -Destination path so as to signal that the target path is meant to be a _directory_, in which case you'll at least get an error if no such directory exists yet.
Although it would technically be a breaking change, it would make sense to default to assuming a container (directory) as the target path in case multiple paths / a wildcard-based path is specified as input, possibly complemented with a new switch such as -CreateOnDemand so as to create the container (directory) on demand.
Thanks for declaration.
But why does it work if Path has subdirectorys?
I don't think a new switch is necessary.
It is documented that a new folder is created if the destination is not available (Copy-Item Doc)
If _Copy-Item -Path "C:\Logfiles*" -Destination "C:\Drawings\Logs"_ worked as expeced, it would match the current documentation.
Also you don`t need the flag "-Recurse" for "Copy all files to a new folder" as described in the note of example 3.
Should I make a new documentation issue for that or wait for further feedback here?
Also you don't need the flag "-Recurse" for "Copy all files to a new folder" as described in the note of example 3
Yes, please open a documentation issue for that.
The short of it is:
C:\Logfiles\* _with_ -Recurse copies all files and all subdirectories _and their subtrees_.
C:\Logfiles\* _without_ -Recurse, copies all files and all subdirectories _as empty directories_.
If you want to copy _files only_, you need to use something like Get-ChildItem C:\Logfiles -File | Copy-Item ...
It is documented that a new folder is created if the destination is not available
This applies if the source path is a _directory_ or at least _has directories among the items that a wildcard expression resolves to_.
If you explicitly pass _multiple_ -Path / -LiteralPath arguments, it is the type of the _first_ item that determines whether a non-existent destination path is considered a file or a directory.
For a _single_ directory and file, respectively, it makes sense to create a directory / a file (after all, Copy-Item file.txt file1.txt should _not_ create a directory named file1.txt and copy file.txt into it).
The current behavior gets messy with _multiple_ source paths, however:
_All-files_ source paths make Copy-Item consider a non-existing destination a _ single file_.
_All-directories_ source paths make Copy-Item consider a non-existing destination a _ single directory_.
-Recurse, this means little more than creating the destination directory, without contents)Copy-Item: Container cannot be copied onto existing leaf item._Mixed-type_ sources resulting from wildcard expressions make Copy-Item also consider a non-existing destination a _single directory_.
This means that all _files_ among the source are copied to the new destination directory, and, if -Recurse is specified, the _contents_ of the _first_ among the source _directories_ is copied; again, any subsequent directories cause an error.
Note: Wildcard resolution results in any directories among the matches being listed _first_, which causes the interpretation of the destination as a _directory_; by contrast, if you explicitly pass multiple paths as an _array_ to -Path / -LiteralPath, the _first_ array element's type determines how the destination is interpreted (as stated above); therefore, if you do something like Copy-Item someFile.txt, someSubdir -Destination foo, foo is created as a _file_ (as a copy of someFile.txt) and the subsequent attempt to copy _directory_ someSubDir to _file_ foo then _fails_.
I don't think a new switch is necessary.
The proposed -Create[DestinationAsContainer]OnDemand switch (name negotiable - I'm struggling to come up with one that is both succinct and descriptive) wasn't meant to address the issues above: it was meant as a convenience switch that allows you to unequivocally specify that the destination path should be a _directory_, to be created on demand, that the source items should be _copied into_. For instance, Copy-Item file.txt foo -CreateDestinationContainerOnDemand would allow you to create directory foo on demand rather than creating a _file_ named foo in the absence of a preexisting foo _directory_. The same would apply to Copy-Item somedir foo -Recurse -CreateDestinationContainerOnDemand, which would copy somedir _as a whole_ into foo/ rather than copying _its contents_ to a not-yet-existing foo directory.
What _was_ meant to address the above issues was the following suggestion:
it would make sense to default to assuming a container (directory) as the target path in case multiple paths / a wildcard-based path is specified as input
To flesh this out a bit:
If _literally_ multiple -Path / -LiteralPath source paths are given, _always_ assume that the destination is a _directory_.
If a single -Path argument is given, and that argument is a _wildcard expression_ (e.g., *.txt) rather than a _literal_ (e.g., file.txt), _always_ assume that the destination is a _directory_.
Otherwise, as currently (single file or single directory), assume that the destination is a file or directory, respectively.
Given how the current behavior with multiple source items is both useless and obscure, it's hard to imagine that existing code relies on it, which would make this proposal an acceptable Bucket 3: Unlikely Grey Area change.
Most helpful comment
I agree that the behavior is counter-intuitive.
What happens is that if the
-Destinationargument is a path that _doesn't yet exist_, it is interpreted as a _file_, and it is the _last_ of the input files that ends up in that file.The workaround is to make sure that the target path exists _as a directory_ beforehand.
You can mitigate the problem somewhat if you append a
\or/to the-Destinationpath so as to signal that the target path is meant to be a _directory_, in which case you'll at least get an error if no such directory exists yet.Although it would technically be a breaking change, it would make sense to default to assuming a container (directory) as the target path in case multiple paths / a wildcard-based path is specified as input, possibly complemented with a new switch such as
-CreateOnDemandso as to create the container (directory) on demand.