David I. McIntosh
David I. McIntosh

Reputation: 2130

"get-childitem * -recurse" drops first-level directories

Suppose we have the following directory structure:

~dir00
   |-> dir10
   |     |-> dir20
   |           |-> file1.txt
   |-> dir11
         |-> file2.txt

Now, suppose ~dir00 is the current directory. I would have expected the two commands
get-childitem * -recurse
and
get-childitem -recurse
to produce the same results. However, they do not. The behaviour of the second is what I would expect.

I am trying to write a small library of tools for use with our scripted processes. One tool I need to write is a tool to copy and backup sets of files. I get, as inputs, something that tells me what files/directories/etc. to copy. I have no way of knowing what the user may provide. They may provide a wild-card such as "*", they may provide a file name, they may provide the -recurse parameter, etc. etc. The inputs are fed to get-childitem. The inconsistency of the behaviour of get-childitem when the "path" is just "*" is a big problem. Why does get-childitem suddenly drop the first-level directories when fed a -path of "*" and the -recurse option? (Note that it only drops the first-level directories.) Is there any way I can prevent this odd behaviour?

Now, it gets more bizzare. If we put a file in the root directory, so the file structure becomes

~dir00
   |-> dir10
   |     |-> dir20
   |           |-> file1.txt
   |-> dir11
   |     |-> file2.txt
   |-> file3.txt

then the directories are suddenly NOT dropped. To reproduce this, just execute the following script:

cd $Env:temp
mkdir dir00\dir10\dir20 | out-null
cd dir00
mkdir dir11 | out-null
echo 'hello world 1'>dir10\dir20\file1.txt
echo 'hello world 2'>dir11\file2.txt
$list1 = get-childitem -recurse
echo 'Results of get-childitem -recurse: '
$list1
echo ''
echo 'Number of items:'
$list1.length
echo ''
$list2 = get-childitem * -recurse
echo 'Results of get-childitem * -recurse: '
$list2
echo ''
echo 'Number of items:'
$list2.length
echo ''
echo "hello world 3">file3.txt
$list3 = get-childitem * -recurse
echo 'Results of get-childitem * -recurse: '
$list3
echo ''
echo 'Number of items:'
$list3.length
echo ''

Upvotes: 5

Views: 2724

Answers (2)

nimizen
nimizen

Reputation: 3419

One possible workaround to this anomalous behaviour would be to substitute the asterisk for a period thereby instructing the Get-ChildItem CMDLet to work with the current directory. Something like this:

$suppliedPath = "*"
if($suppliedPath -eq "*"){
    $suppliedPath = $suppliedPath.replace("*", ".")
}
Get-ChildItem $suppliedPath -recurse

Upvotes: 1

HAL9256
HAL9256

Reputation: 13453

This is because the path that you are feeding into Get-ChildItem is different.

When you execute:

Get-ChildItem -Recurse

You are saying the same as:

Get-ChildItem -Path . -Recurse

Or interpreted as: Get Child Item -Path starts at the current directory (dir00)

When you execute:

Get-ChildItem * -Recurse

You are saying, with the *, iterate through all items in the directory, feed those paths to Get-ChildItme, and then Recurse through those items. So the equivalent command that is executed is this:

$items = Get-ChildItem *
Get-ChildItem $items -Recurse

Which works out to:

Get-ChildItem -Path ./dir10 -Recurse
Get-ChildItem -Path ./dir11 -Recurse

Now, what you are seeing is an odd exception (or could be seen as a bug) to this behaviour, and it only happens in this case when you have a root directory that only contains folders and no files. If you create one file in the dir00:

echo 'hello world 1'>test1.txt

And then we execute

Get-ChildItem * -Recurse

It lists exactly the same as Get-ChildItem -Recurse. So you will only get different results only when you have root directories with no files, only folders.

Upvotes: 8

Related Questions