Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
188 views
in Technique[技术] by (71.8m points)

validation - Does PowerShell have a clean way of validating a path to a file to be created?

In Python there are simple one liners that can take a path like C:somefoldersomesubfolderfile.csv, grab the C:somefoldersomesubfolder part, if it exists, and tell you if it's valid. I have to account for a user potentially passing in an absolute path, a relative path, or no path at all and the file just writing to the same directory. Some potential user input:

  • ..an_invalid_foldersomething.csv
  • C:
  • an invalid foldersomething.csv
  • something.csv
  • some_absolute_pathsomething.csv

In PowerShell I found this surprisingly cumbersome. I found things like Split-Path have strange behaviors - Ex: if you pass only C: and then run split path with the leaf option it will tell you C: is the leaf. Now, I understand why they do that but it makes solving the above a bit ugly. Below is what I came up with - does PowerShell not have something like the os.path library that more cleanly handles all these situations?

$ParentPath = $(Split-Path -Path $OutputFilePath -Parent)
if ($ParentPath -ne "") {
  if (-not $(Test-Path -PathType Container $ParentPath)) {
    Write-Error "The path you provided for $($OutputFilePath) is not valid." -ErrorAction Stop
  }
}

if (Test-Path $(Split-Path -Path $OutputFilePath -Leaf) -PathType Container) {
  Write-Error "You must provide a filename as part of the path. It looks like you only provided a folder in $($OutputFilePath)!" -ErrorAction Stop
}

Try { [io.file]::OpenWrite($outfile).close() }
Catch { Write-Error "It looks like you may not have permissions to $($OutputFilePath). We tried to open a file object there and the test failed." -ErrorAction Stop }
question from:https://stackoverflow.com/questions/66067993/does-powershell-have-a-clean-way-of-validating-a-path-to-a-file-to-be-created

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
  • There is undoubtedly room for improvement in PowerShell's *-Path cmdlets, notably with respect to allowing the specified paths to (partially) not exist (yet) - for example, see the Convert-Path-related GitHub proposal #2993.

  • While direct use of the methods of the static .NET System.IO.Path class offers a way around that, a notable - and unavoidable - pitfall is that .NET's current directory usually differs from PowerShell's, which means:

    • You should generally always pass full paths to .NET methods (with existing paths, passing a path to Convert-Path first can ensure that). In your case, the [io.file]::OpenWrite() call may either fail or create the file elsewhere if given a relative (or file-name-only) path.

      • Additionally, .NET knows nothing of PowerShell-specific drives (created with New-PSDrive), so paths based on such drives must be converted to file-system-native paths - again, Convert-Path does that.

      • To get PowerShell's current directory as a native file-system path, use $PWD.ProviderPath (or, if there's a chance that the current location is that of a provider other than the file-system, such as the registry on Windows: (Get-Location -PSProvider FileSystem).ProviderPath).

    • Similarly, [System.IO.Path]::GetFullPath() specifically resolves a relative path relative to .NET's current directory, so it generally won't work as expected (unless you explicitly synchronize the current directories first, with [Environment]::CurrentDirectory = $PWD.ProviderPath).

      • In PowerShell (Core) 7+ only, you can work around the problem with the optional (.NET Core-only) 2nd parameter that allows passing in a reference directory:

        • [System.IO.Path]::GetFullPath('foo', $PWD.ProviderPath)

Here's a slightly simpler solution than yours, which partly relies on the underlying .NET exceptions to provide meaningful error messages:

try { 
  $null = New-Item -ErrorAction Stop -Type File $OutputFilePath
} catch { 
  Throw "`"$OutputFilePath`" is not a valid -OutFilePath argument: " + $(
    if (Test-Path -PathType Container -LiteralPath $OutputFilePath) { 
      "Please specify a path to a *file*, not just a directory." 
    } else  {
      $_.Exception.Message
    }
  )
}

# Note: As with your approach, file $OutFilePath now exists as an empty, 
#       in a closed state.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.8k users

...