2

I've referenced this question to get me this far: redirecting test-path output to text file

I'm essentially using the same examples provided, I just need to create an output of the invalid file paths also.

I'm attempting to check if files exist via UNC paths. so I'm targeting specific files (C:\Users\Goalie\Desktop\folder\1.txt, \2.txt, \3.txt) I know each file path already, I'm just attempting to see if the files at those UNC paths are actually there or not.

\paths.txt includes several UNC file paths. Ex:

C:\Users\Goalie\Desktop\folder\1.txt
C:\Users\Goalie\Desktop\folder\2.txt
C:\Users\Goalie\Desktop\folder\3.txt

The below code currently works, however, only for the valid file paths. I need the invalid file paths as well.

$inputfile = "C:\Users\Goalie\Desktop\folder\paths.txt"
$outputexistingfiles = "C:\Users\Goalie\Desktop\folder\existingfiles.txt"
$outputmissingfiles = "C:\Users\Goalie\Desktop\folder\missingfiles.txt"


Get-Content $inputfile |
    Where-Object {Test-Path $_} |
        Out-File -FilePath $outputexistingfiles -Append

Note: This will be used to test several million paths in its final stage. Is this the most efficient method? I've read that the below version of test-path is faster, however, I'm not sure how to incorporate it into the above as it outputs either True or False, instead of the actual UNC path.

$inputfile = "C:\Users\Goalie\Desktop\folder\paths.txt"
$filepaths = Get-Content $inputfile

$filepaths.ForEach({Test-path $_ -PathType leaf}) | Out-File -FilePath $outputmissingpaths -Append

Many thanks for any help. -Goalie

Goalie
  • 23
  • 4
  • I assume, given that many paths, you want to find both existing and missing files in a single pass? Are there (m)any paths that are descendants of each other? If you find that ```C:\X\``` doesn't exist then you know ```C:\X\Y\``` and ```C:\X\Y\Z\``` cannot, either. – Lance U. Matthews Nov 11 '21 at 23:26
  • Yes, I'd ideally like to identify both in one pass. I should probably elaborate on my question a bit. I'm attempting to check if files exist via UNC paths. so I'm targeting specific files (C:\Users\Goalie\Desktop\folder\1.txt, 2.txt, 3.txt) I know each file path already, I'm just attempting to see if the files at those UNC paths are actually there or not. Hope that clarifies. – Goalie Nov 11 '21 at 23:29
  • Right, that much was clear from the question. Whether it's UNC paths or mapped drives or local drives doesn't really change anything (as long as the current user has access to the network shares). Are all these files to test for existence in the same directories (i.e. ```C:\Users\Goalie\Desktop\folder\``` and whatever the UNC directory is), or are they all over the place? – Lance U. Matthews Nov 11 '21 at 23:35
  • Ok, sorry, first time user :). They are all under a single main directory, however there are several subdirectories existing beneath. – Goalie Nov 11 '21 at 23:37

2 Answers2

3

This should should list the missing paths:

Get-Content $inputfile |
    Where-Object {!(Test-Path $_)} |
        Out-File -FilePath $outputmissingfiles -Append
Mogash
  • 130
  • 1
  • 7
2

The answer to the question in your post's title is: Test-Path itself has no switch for inverting its logic, but you can pass a call's output to the -not (!) operator: -not (Test-Path $_).

This will be used to test several million paths in its final stage. Is this the most efficient method?

Your use case calls for:

$inputfile = 'C:\Users\Goalie\Desktop\folder\paths.txt'

# Initialize the output file writers.
# Note: Be sure to use *full* paths, because .NET's working directory
#       usually differs from PowerShell's
$outExisting = [System.IO.StreamWriter] 'C:\Users\Goalie\Desktop\folder\existingfiles.txt'
$outMissing =  [System.IO.StreamWriter] 'C:\Users\Goalie\Desktop\folder\missingfiles.txt'

switch -File $inputfile {
  default {
    if ([System.IO.File]::Exists($_)) {
      $outExisting.WriteLine($_)
    } else {
      $outMissing.WriteLine($_)
    }
  }
}

$outExisting.Close(); $outMissing.Close()
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    This is great, I tested in my environment and it worked. Thank you for your input and assistance. Side question, are there any metrics that can be aggregated for how long a job takes to complete? – Goalie Nov 11 '21 at 23:57
  • Capture time at beginning and end then subtract. is the easiest way. Of course you could use Measure-Object but seems like a lot of un-necessary overhead. – RetiredGeek Nov 12 '21 at 01:09
  • I'm glad to hear it, @Goalie; my pleasure. PowerShell's cmdlet for timing a command's execution is [`Measure-Command`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/measure-command) (not to be confused with [`Measure-Object`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/measure-object)). However, a _single_ timing can be deceptive, so its better to average _multiple_ timings - see [this answer](https://stackoverflow.com/a/68576802/45375). – mklement0 Nov 12 '21 at 01:55
  • 1
    Thank you, I'll take a look at Measure-Command and see what my options are. Thanks again for the quick help! – Goalie Nov 12 '21 at 03:50