0

I'm trying to check a series of directories and subdirectories to see if there are two or more files with the same name in the same folder. I think my issue is how I'm trying to validate a string.

For the following test directory:

  • |-- C:\Test\
    • |--C:\Test\YY\
      • |--C:\Test\YY\xx.log
      • |--C:\Test\YY\xx.txt
    • |-- C:\Test\ZZ\
    • |-- C:\Test\ZZ.log
    • |-- C:\Test\ZZ.txt

I need my code to find xx.log and ZZ.log. I can include a check against $_.PSisContainer (but I didn't think it was necessary).

ForEach ($item in (gci "C:\Test\*" -recurse)) {
    If ($item.extension -notmatch "txt" -AND $item.basename+".txt" -eq $True) {
        Write-Host $item.fullname
        } 
    }

$item.basename+".txt" provides the right string but I can't use that string to validate the existence of the file.

Can anyone help correct my code? I'd like to learn how to handle concatenated strings like this--it's a trick I think would be useful in other areas.

2 Answers 2

1

This not intended as an answer, rather a comment, but SO is not allowing me to add comments right now :(

R_C_III - I guess there are two errors in the original code.

Firstly, it does not build the complete file path (i.e. DirectoryName + BaseName + .TXT). Rather than concatenate strings to do this, Keith has used PowerShell's ability to perform value substitutions inside double-quoted strings. e.g.

$s = "there"
write-host "hello $s"

results in

hello there

To insert object properties into a string in this way it's necessary to use sub-expressions as Keith explains.

$file = get-item "c:\somefile.txt"
write-host "$($file.DirectoryName)\$($file.BaseName).NEW"

results in

c:\somefile.NEW

Secondly (as per my comment on Keith's answer), the original code does not check for the existence of the '.txt' version of the file. The second clause in the IF statement attempts to equate the modified filename with $True ($item.basename+".txt" -eq $True). This clause will always evaluate as false.

Keith's modification adds the 'Test-Path' CmdLet which, in this instance, checks for the existence of the '.txt' file.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! Great answer! I narrowed down the core issue: could you explain the following example? $item.basename+".txt" produces a System.String of ZZ.txt test-path $item.basename+".txt" a positional parameter error cannot be found that accepts argument '+.txt' and write-host $item.basename+".txt" produces ZZ +.txt $($item.basename+".txt") produces a System.String of ZZ.txt and write-host shows ZZ.txt From the outside these are supposed to be the same but write-host shows differently. I think this is my problem in the OP. Are all strings not created equal? @andyb @keith-hill
Strongly suspect this is something to do with the PowerShell parsing modes. I refer you to one of Keith's excellent articles (rkeithhill.wordpress.com/2007/11/24/…) and also 'get-help about_parsing'
1

Try this:

gci C:\Test -recurse -file | Where {$_.extension -ne ".txt" -AND (Test-Path "$($_.DirectoryName)\$($_.BaseName).txt")}

You don't need the initial Foreach statement as PowerShell commands that output data can be used directly at the start of a pipeline. Then you filter pipeline objects with the Where command.

3 Comments

Works great! Thanks! Could you explain how the "$($_.DirectoryName)\$($_.BaseName).txt" works though? How does the $() do what my $_.Basename+".txt" did not?
To evaluate an expression, such as a property reference, inside a string you need to use a subexpression i.e. $().
R_C_III - It looks to me like your original expression is performing trying to equate a string ($item.basename+".txt") and a boolean ($True). Keith has added the Test-Path CmdLet which checks for the existence of the file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.