使用文件和目录的函数的惯用参数类型

时间:2016-03-18 15:16:55

标签: powershell

如果我正在写"惯用" PowerShell,我将使用哪些参数类型用于处理文件或目录的函数?

例如,我制作了一个包含此功能的模块:

$bookmarks = @{}
$bookmarkKeys = @{}

function Set-Bookmark {
    param(
        [Parameter(Mandatory = $true)]
        [string] $Id,
        [System.Management.Automation.DirectoryInfo] $Path = (Get-Location))
    $script:bookmarks[$Id] = $Path
    $script:bookmarkKeys[$Path.Path] = $Id
}

麻烦的是,以下不起作用:

PS>Set-Bookmark -Id Code -Path C:\Code
Set-Bookmark : Cannot process argument transformation on parameter 'Path'.
Cannot convert the "C:\Code" value of type "System.String" to type
"System.Management.Automation.PathInfo".
At line:1 char:29
+ Set-Bookmark -Id Code -Path C:\Code
+                             ~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Set-Bookmark], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-Bookmark

奇怪的是,这也不是(但原因略有不同):

PS>Set-Bookmark -Id Code -Path (gi C:\Code)
Set-Bookmark : Cannot process argument transformation on parameter 'Path'.
Cannot convert the "C:\Code" value of type "System.IO.DirectoryInfo" to type
"System.Management.Automation.PathInfo".
At line:1 char:29
+ Set-Bookmark -Id Code -Path (gi C:\Code)
+                             ~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Set-Bookmark], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-Bookmark

那么我应该将我的参数实际定义为字符串(即最小公分母),然后尝试将它们转换/解析为更有意义的类型?这听起来不对,因为如果我处理Get-Item之类的结果而感到羞耻,那么他们会因为传入而被降到string,仅用于该函数再次解析为更高级别的类型。

3 个答案:

答案 0 :(得分:4)

我认为你想要使用[IO.DirectoryInfo]类型。这对我来说很好:

function t {
  param(
    [IO.DirectoryInfo] $d
  )
  "You passed $d"
}

t (Get-Item "C:\Windows")

对于文件,您可以使用[IO.FileInfo],但这不支持通配符。

答案 1 :(得分:1)

您在实际代码中使用了System.Management.Automation.PathInfo类型,而不是System.Management.Automation.DirectoryInfo,否则您将获得TypeNotFound例外。 System.Management.Automation命名空间中没有DirectoryInfo个类。但是,正如@Bill_Stewart已经提到的那样,文件夹对象无论如何都是System.IO.DirectoryInfo类型。 PathInfo类适用于PowerShell路径,它们不一定是文件系统路径(例如,考虑证书或注册表provider)。

如果你想要一个可以同时接受文件(System.IO.FileInfo)和文件夹(System.IO.DirectoryInfo)的参数,你需要使参数类型成为两种类型的公共基类(例如{{3 }}):

function Set-Bookmark {
    Param(
        [Parameter(Mandatory=$true)]
        [string] $Id,
        [Parameter(Mandatory=$false)]
        [IO.FileSystemInfo]$Path = (Get-Location)
    )
    ...
}

System.String(因为文件和文件夹对象都可以转换为字符串,反之亦然):

function Set-Bookmark {
    Param(
        [Parameter(Mandatory=$true)]
        [string] $Id,
        [Parameter(Mandatory=$false)]
        [ValidateScript({Test-Path -LiteralPath $_})]
        [string]$Path = (Get-Location)
    )
    ...
}

请注意,当使用String作为-Path参数的类型时,您需要自己System.IO.FileSystemInfo参数以防止传递非有效路径的参数。另请注意,使用IO.FileSystemInfo作为参数类型时,参数将不接受路径字符串(即Set-Bookmark -Id 42 -Path "C:\some\path"将失败)。

底线:

惯用参数类型取决于您希望函数接受的输入。如果它的文件和文件夹对象使用System.IO.FileSystemInfo。如果它的路径使用use System.String,请验证输入,并根据需要将路径字符串(返回)转换为文件/文件夹对象。

答案 2 :(得分:1)

从可用性的角度来看,我总是发现将文件和目录参数声明为类型string更容易。 PowerShell如此灵活的原因在于能够结合来自不同来源的功能。我不知道您的目标受众是谁,但假设用户想要在Set-Bookmark中为文本文件中的条目调用。如果它接受了一个字符串,那么调用该函数要简单得多:

$id = 0
Get-Content 'bookmarks.txt' | For-EachObject { Set-Bookmark -id $i++ -Path $_ } 

还有一个事实是您可能并不总是使用文件提供程序,因此假设您的Path始终表示文件路径将限制此函数的有用性。例如,如果您使用的是Microsoft SQL提供程序,则可能希望您的函数为SQL提供程序中的路径提供书签。 (使用Test-Path的第二个解决方案可行。)同样,我不了解您的目标受众,但值得考虑。