Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Copy-Item

3,319 views
Skip to first unread message

VRSki

unread,
Aug 8, 2007, 8:12:26 PM8/8/07
to
Please help!

I am trying to use Copy-Item to recursively copy a directory. Here is the
example:

Initial Directory Structure

1.
c:\
|--Test [folder]
| |
|--src [folder]
|
|-- A [folder]
| |
| |-- 1.txt [file]
|
|-- 2.txt [file]


Here is what I need to happen

2.
c:\
|--Test [folder]
| |
|--dest [folder]
| |
| |-- A [folder]
| | |
| | |-- 1.txt [file]
| |
| |-- 2.txt [file]
|
|--src [folder]
|
|-- A [folder]
| |
| |-- 1.txt [file]
|
|-- 2.txt [file]

So, here is the command I am using:

copy-item c:\test\src\ c:\test\dest\ -recurse -force

Great! This works! But now, if I try to execute exactly the same command
(expecting no changes to the directory structure) I get an addtional
directory \src under \dest

3.
c:\
|--Test [folder]
| |
|--dest [folder]
| |
| |-- A [folder]
| | |
| | |-- 1.txt [file]
| |
| |-- 2.txt [file]
|
|--src [folder]
|
|-- A [folder]
| |
| |-- 1.txt [file]
|
|-- 2.txt [file]
|
|--src [folder]
|
|-- A [folder]
| |
| |-- 1.txt [file]
|
|-- 2.txt [file]

Fine. I can sort of understand the difference in copying a folder when the
destination exists vs. when it's not there...

So, I delete \src from under \dest and try this:
copy-item c:\test\src\* c:\test\dest\ -recurse -force

It works! I get what I expected -- sample 2. So, just to verify it, I delete
folder \a from under \dest and try the same command again.
copy-item c:\test\src\* c:\test\dest\ -recurse -force

Works again! So just to test the whole thing from scratch I delete the
entire folder \dest and run exactly the same command:
copy-item c:\test\src\* c:\test\dest\ -recurse -force

Oh no!! Now the folder \A (I am expecting to be under \dest) is missing, but
2.txt is there: all the directories were flattened.

4.
c:\
|--Test [folder]
| |
|--dest [folder]
| |
| |-- 1.txt [file]
| |
| |-- 2.txt [file]
|
|--src [folder]
|
|-- A [folder]
| |
| |-- 1.txt [file]
|
|-- 2.txt [file]


I run exectly the same command and now I get my folder \A under \dest.


So, what am I doing wrong? Is Copy-Item even meant to copy folders? All I
want is the consistent behavior (with preferably the same command syntax):
dest is created if it doesn't exist, and if it does exist, all \src files
and directories should be under \dest.

Please help!

Thanks,
VR


Oisin Grehan

unread,
Aug 9, 2007, 11:21:26 AM8/9/07
to

Hi VR,

You say:

>> Works again! So just to test the whole thing from scratch I delete the
>> entire folder \dest and run exactly the same command:
>> copy-item c:\test\src\* c:\test\dest\ -recurse -force

However, this is NOT the same as your initial command:

>> So, here is the command I am using:
>> copy-item c:\test\src\ c:\test\dest\ -recurse -force

The difference is the asterisk.

In the former case, you are copying everything within src\ e.g. the
source is a _collection_, and the first item retrieved with the
wildcard is then used to create "dest" because it doesn't exist yet.
The remaining items in the collection are then placed in dest (which
create from "A"). Yes, it's counterintuitive; some might say
unexpected or even useless behaviour.

In the latter case (your original command), the source resolves to a
single item, the directory "src." This is then mapped to the as yet
nonexistant "dest" and you should get the expected behaviour.

This behaviour IMO, is an artifiact of the provider and object
pipeline model that powershell uses. You have to get used to the idea
that the navigational context is a bit weird compared to other shells;
it's explicit as opposed to implicit, since the filesystem is one of
many contexts that can be used. This brings with it some weird
behaviours since the targets of any given path are handled with a
combination of powershell's generic grammar and the command itself, as
opposed to being entirely handled by the command in shells like
command.com/cmd.exe.

Hope this helps,

- Oisin

VRSki

unread,
Aug 10, 2007, 4:43:30 PM8/10/07
to
Oisin,

Thank you for your post.

You say:

>>> Works again! So just to test the whole thing from scratch I delete the
>>> entire folder \dest and run exactly the same command:
>>> copy-item c:\test\src\* c:\test\dest\ -recurse -force
>
> However, this is NOT the same as your initial command:
>

I understand and agree, it's not the original command. I was merely pointing
out the fact that at that given step I have achieved the desired result.

Now, the question still stands. What would be the syntax of the command to
copy the \src directory into \dest so that the outcome would be the same
regardless of whether \dest exists or not.

I guess I can accept the fact that the syntax may differ between the two
cases, but can somebody tell me what would that syntax be?

Thanks,
Vic


"Oisin Grehan" <ois...@gmail.com> wrote in message
news:1186672886.1...@w3g2000hsg.googlegroups.com...

Kiron

unread,
Aug 11, 2007, 1:20:54 AM8/11/07
to
To work around this bug?/feature? in Copy-Item you can check the existence
of the destination then execute accordingly:

if (test-path c:\test\dest\)
{


copy-item c:\test\src\* c:\test\dest\ -recurse -force
}

else
{


copy-item c:\test\src\ c:\test\dest\ -recurse -force
}

But if you want to save some typing and time, this function will get the
results you expect.
First it deletes the ending asterisk of the source path because if the
destination does not exist Copy-Item ignores the source's child
subdirectory. (If there is no asterisk at the end of the source path it is
unchanged)
Then it checks for the existence of the destination directory, if it exists
the switch statement adds the asterisk to the source path.
Finally Copy-Item gets the right variation of the source path and copies the
child items.

function xCopy
(
[string]$src = $(throw "Specify the source directory"),
[string]$dest = $(throw "Specify the destination diirectory")
)
{
$src = $src -replace '\*$'
if (test-path $dest)
{
switch -regex ($src)
{
'\\$' {$src = "$src*"; break}
'\w$' {$src = "$src\*"; break}
default {break}
}
}
copy-item $src $dest -recurse -force
}

You can call the function like:
xCopy c:\test\src c:\test\dest\
xCopy c:\test\src\ c:\test\dest\
xCopy c:\test\src\* c:\test\dest\

...or minimally naming the parameters (position does not matter)
xCopy -d c:\test\dest\ -s c:\test\src
xCopy -d c:\test\dest\ -s c:\test\src\
xCopy -d c:\test\dest\ -s c:\test\src\*

--
Kiron

VRSki

unread,
Aug 13, 2007, 11:38:38 AM8/13/07
to
Thanks Kiron.

"Kiron" <Ki...@HighPlainsDrifter.com> wrote in message
news:6CAEDDC7-0F1A-4B21...@microsoft.com...

0 new messages