PowerShell 是否有一种干净的方法来验证要创建的文件的路径?

Gra*_*ell 2 validation powershell

在 Python 中,有一些简单的衬垫可以采用类似 的路径C:\somefolder\somesubfolder\file.csv,抓取C:\somefolder\somesubfolder\零件(如果存在),并告诉您它是否有效。我必须考虑用户可能传递绝对路径、相对路径或根本不传递路径并且文件仅写入同一目录。一些潜在的用户输入:

  • ..\an_invalid_folder\something.csv
  • C:\
  • an invalid folder\something.csv
  • something.csv
  • some_absolute_path\something.csv

在 PowerShell 中,我发现这非常麻烦。我发现像 Split-Path 这样的东西有奇怪的行为 - 例如:如果你只通过C:\然后使用 leaf 选项运行 split path ,它会告诉你C:\是叶子。现在,我明白他们为什么这样做,但这使得解决上述问题变得有点难看。下面是我的想法 - PowerShell 没有类似os.path库的东西可以更干净地处理所有这些情况吗?

$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 }
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 5

  • PowerShell 的cmdlet无疑还有改进的空间*-Path,特别是在允许指定路径(部分)不存在方面- 例如,请参阅Convert-Path相关的GitHub 提案 #2993

  • 虽然直接使用静态 .NETSystem.IO.Path类的方法提供了一种解决方法,但一个值得注意且不可避免的陷阱是.NET 的当前目录通常与 PowerShell 的不同,这意味着:

    • 通常,您应该始终将完整路径传递给 .NET 方法(对于现有路径,将路径传递给Convert-Path第一个可以确保这一点)。在您的情况下, 如果给定相对(或仅文件名)路径,则调用可能会失败或在其他位置[io.file]::OpenWrite()创建文件。

      • 此外,.NET 对PowerShell 特定的驱动器(使用 创建的)一无所知New-PSDrive,因此基于此类驱动器的路径必须转换为文件系统本机路径 - 再次Convert-Path这样做。

      • 要将 PowerShell 的当前目录作为本机文件系统路径,请使用$PWD.ProviderPath(或者,如果当前位置有可能是文件系统以外提供程序的位置,例如Windows 上的注册表(Get-Location -PSProvider FileSystem).ProviderPath:) 。

    • 同样,[System.IO.Path]::GetFullPath()专门解析相对于.NET当前目录的相对路径,因此它通常不会按预期工作(除非您首先使用 显式同步当前目录[Environment]::CurrentDirectory = $PWD.ProviderPath)。

      • 仅在PowerShell (Core) 7+中,您可以使用允许传入引用目录的可选(仅限 .NET Core)第二个参数来解决该问题:

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

这是一个比您的解决方案稍微简单的解决方案,它部分依赖于底层 .NET 异常来提供有意义的错误消息:

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.
Run Code Online (Sandbox Code Playgroud)