0

I am having some trouble validating a file input in a script. Using the following function

Function pathtest {
    [CmdletBinding()]
    param (
        [ValidateScript({
                if (-Not ($_ | Test-Path -PathType Leaf) ) {
                    throw "The Path argument must be a file. Folder paths are not allowed."
                }
                return $true
            })]
        [System.IO.FileInfo]$Path
    )

    Write-Host ("Output file: {0}" -f $Path.FullName)
}

Then I call the function with these two input files

pathtest -Path c:\temp\test.txt
pathtest -Path c:\temp\test.csv

The first one (test.txt) returns the path, but the second one (test.csv) returns an error:

PS C:\> pathtest c:\it\test.txt
Output file: c:\it\test.txt
PS C:\> pathtest c:\it\test.csv
pathtest : Cannot validate argument on parameter 'Path'. The Path argument must be a file. Folder paths are not
allowed.
At line:1 char:10
+ pathtest c:\it\test.csv
+          ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [pathtest], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,pathtest

Any idea what's up with this?

StackExchangeGuy
  • 741
  • 16
  • 36
  • Is there something you're not showing us? i.e. a path with spaces and the path not quoted ? Your code looks perfectly fine – Santiago Squarzon Dec 02 '22 at 19:59
  • Nope, that's it. Copy/paste into my shell and this is what I got. I also pasted into PowerShell on another machine and saw the same behavior. Odd, yeah? – StackExchangeGuy Dec 02 '22 at 20:05
  • 1
    well, your code has nothing wrong with it. the only possible explanation is that A. the 2nd path is actually wrong or B. you have a folder named as a file :D – Santiago Squarzon Dec 02 '22 at 20:11
  • 1
    What does `[System.IO.File]::GetAttributes('c:\it\test.csv')` output ? – Santiago Squarzon Dec 02 '22 at 20:12
  • If the file exists, I get "Archive". But "Exception calling "GetAttributes" with "1" argument(s): "Could not find file 'c:\it\test.csv'."" when the file does not exist. – StackExchangeGuy Dec 02 '22 at 20:40

1 Answers1

1

Test-Path -Leaf also returns $false when the specified path doesn't exist.

Therefore, you need to test for existence separately, so as to distinguish between an existing path that happens to be a folder and a non-existent path.

Try the following instead:

Function pathtest {
  [CmdletBinding()]
  param (
    [ValidateScript({
        $item = Get-Item -ErrorAction Ignore -LiteralPath $_
        if (-not $item) {
          throw "Path doesn't exist: $_"
        }
        elseif ($item.PSIsContainer) {
          throw "The Path argument must be a file. Folder paths are not allowed."
        }
        return $true
      })]
    [System.IO.FileInfo] $Path
  )

  Write-Host ("Output file: {0}" -f $Path.FullName)
}
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • When the file does not exist: pathtest : Cannot validate argument on parameter 'Path'. Path doesn't exist: c:\temp\test.txt. I don't understand why it isn't getting to the 'return' – StackExchangeGuy Dec 02 '22 at 22:02
  • 1
    @StackExchangeGuy, `throw` instantly aborts execution of the script block, which is also what your own code relies on. – mklement0 Dec 02 '22 at 22:08