views:

34

answers:

2

Imagine I have a directory structure like so:

parentDir\dirA\foo\
parentDir\dirB\foo\
parentDir\dirC\
parentDir\dirD\bar\foo\
parentDir\dirE\foo\
parentDir\dirF\

I want to select only the directories that a) are immediate children of parentDir, and b) have a foo directory as an immediate child.

So dirs A, B, and E qualify, whilst C, D, and F don't.

I first tried this powershell script:

$rootDir = gi(".")
dir -include "*foo*" -recurse | ? {$_.PSIsContainer -eq $true} | % {$_.Parent} 
    | ? { $_.Parent -eq $rootDir } 

It finds all foo items below the root dir, filters out non-directories, goes up one to the intermediate directories, then filters out any directory which is not a child of the root dir.

This returns an empty list.

However if I change the last where clause as follows:

? { $_.Parent.FullName -eq $rootDir.Fullname }

It works, and I get the correct directories output.

So my question is, why won't a direct compare between directory objects work? It may seem like a little thing but it implies there's some hole in my understanding of powershell objects.

(Also, feel free to critique my powershell coding style in the scripts, or point out quicker/more correct ways of doing this)

+1  A: 

Two different instances of the DirectoryInfo class are not considered equal, even if they point to the same path. Two strings on the other hand, are always considered equal if they contain the same letters, in the same order.

-Oisin

x0n
+2  A: 

When comparing .NET objects, there are a number of factors at play. First, the compare can be a simple reference equality comparison i.e. does this variable reference the exact same object that the other variable references. In many cases (most reference types), this is the default behavior for equality. There are other types (value types) however that do equality based the value of the fields in an object e.g. DateTime, TimeSpan, Int32, Double, etc. Then there are objects override the default behavior by overriding operator == or and/or overriding Equals() virtual method. String is a reference type that overrides these to provide "value-based" equality.

See if this does the trick:

$rootDir = gi .
gci . -r *Foo* | ?{$_.PSIsContainer -and $_.Name -eq 'Tools' -and `
                   $_.Parent.Name -eq $rootDir.Name}
Keith Hill
Thanks. I wondered if -eq was a reference comparitor or value, and if there was some way to make it be the latter. But from what you're saying it's down purely to the .Net class that I'm using. In the future I'll have to check MSDN to see if the class I'm using supports equality (in this case System.IO.DirectoryInfo).
tenpn