参数ValueFromPipeline和更改位置

时间:2014-08-28 13:40:51

标签: powershell parameters parameter-passing

我在定义参数位置时遇到了一些问题。例如,当我将$Folder传递给我的函数时,其他参数的位置会发生变化。

通常情况下,参数$Folderposition=0,但是当某些内容传递到函数时,它没有考虑到位置0在管道符号之前不再位于其后面。

该功能可用于所有情况,包括或不包括开关$Recurse$Inheritance设置为On/Off。主要目的是设置权限或设置文件夹的继承。两者的结合也是可能的。

[CmdletBinding(SupportsShouldProcess=$True,DefaultParametersetName="SetPermissions")]
Param(
    [parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_ -PathType Container})]
    [String[]]$Folder,

    [parameter(Mandatory=$true,Position=1,ParameterSetName='SetPermissions')]
    [parameter(Mandatory=$false,ParameterSetName='SetInheritance')]
    [ValidateNotNullOrEmpty()]
    [String]$SAMaccountName,

    [parameter(Mandatory=$true,Position=2,ParameterSetName='SetPermissions')]
    [parameter(Mandatory=$false,ParameterSetName='SetInheritance')]
    [ValidateNotNullOrEmpty()]
    [ValidateSet('ReadAndExecute','Modify','FullControl','ListFolderContents')]
    [String]$Grant,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Domain = 'MyDomain',

    [parameter(Mandatory=$false,Position=3,ParameterSetName='SetPermissions')]
    [parameter(Mandatory=$true,Position=1,ParameterSetName='SetInheritance')]
    [ValidateNotNullOrEmpty()]
    [ValidateSet('On','Off')]
    [String]$Inheritance,

    [Switch]$Recurse
)

所有可能的选项:

# SetPermissions
Set-ACLspecial -Folder 'C:\Folder' -SAMaccountName 'Bob' -Grant ReadAndExecute
Set-ACLspecial -Folder 'C:\Folder' -SAMaccountName 'Bob' -Grant ReadAndExecute -Recurse
Set-ACLspecial -Folder 'C:\Folder' -SAMaccountName 'Bob' -Grant ReadAndExecute -Inheritance On
Set-ACLspecial -Folder 'C:\Folder' -SAMaccountName 'Bob' -Grant ReadAndExecute -Inheritance On -Recurse

Set-ACLspecial 'C:\Folder' 'Bob' ReadAndExecute
Set-ACLspecial 'C:\Folder' 'Bob' ReadAndExecute -Recurse
Set-ACLspecial 'C:\Folder' 'Bob' ReadAndExecute On
Set-ACLspecial 'C:\Folder' 'Bob' ReadAndExecute On -Recurse

'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute
'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute -Recurse
'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute On
'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute On -Recurse

# SetInheritance
Set-ACLspecial 'C:\Folder' -Inheritance Off
Set-ACLspecial 'C:\Folder' -Inheritance Off -Recurse
'C:\Folder' | Set-ACLspecial -Inheritance Off
'C:\Folder' | Set-ACLspecial -Inheritance Off -Recurse

目前的语法:

Set-HCaclTEST [-Folder] <String[]> [-SAMaccountName] <String> [-Grant] <String> [-Domain <String>] [[-Inheritance] <String>] [-Recurse] [-WhatIf] [-Confirm] [<Common
Parameters>]

Set-HCaclTEST [-Folder] <String[]> [-SAMaccountName <String>] [-Grant <String>] [-Domain <String>] [-Inheritance] <String> [-Recurse] [-WhatIf] [-Confirm] [<CommonPa
rameters>]

错误:

'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute
# Test-Path on 'Bob' is not working... PowerShell sees Bob as the variable `$Folder`, but it's not.

2 个答案:

答案 0 :(得分:5)

The Position value is only used to match unnamed parameters.通过管道传递的参数被命名,因此在进行此计算时会被忽略。在您的示例中,第一个未命名的参数是Bob,因此会将其分配给参数$Folder,因为该参数的位置为0。最佳做法是始终在脚本中使用参数名称。这使它们更容易理解。在控制台上使用位置参数来节省键击次数。

从我在PowerShell基础cmdlet中看到的情况来看,采用管道输入的参数通常也不是位置参数。 (可能正是出于这个原因。)当不通过管道传递时,必须通过名称传递可以通过管道输入的参数。从Position=0参数中删除$Folder

    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_ -PathType Container})]
    [String[]]
    $Folder,

答案 1 :(得分:2)

Hopefull你可以用它来遵循参数绑定中使用的逻辑。它摘自Windows Powershell in Action布鲁斯帕耶特。

  1. 绑定所有命名参数 - 在命令行中查找以破折号开头的所有未加引号的标记。如果令牌以冒号结尾,则需要参数。如果没有冒号,请查看参数的类型并查看是否需要参数。将实际参数的类型转换为参数所需的类型,并绑定参数。
  2. 绑定所有位置参数 - 如果命令行上有任何未使用的参数,请查找采用位置参数并尝试绑定它们的未绑定参数。
  3. 通过精确匹配的值从管道绑定 - 如果命令不是管道中的第一个命令,并且仍有未绑定的参数接受管道输入,请尝试绑定到匹配的参数确切的类型。
  4. 如果未绑定,则通过转换值从管道绑定。 - 如果上一步失败,请尝试使用类型转换进行绑定。
  5. 如果未绑定,则按名称与管道绑定并使用完全匹配 - 如果上一步失败,请在输入对象上查找与参数名称匹配的属性。如果类型完全匹配,请绑定参数。
  6. 如果未绑定,则通过名称转换为管道绑定。如果输入对象具有名称与参数名称匹配的属性,并且属性的类型可转换为参数的类型,绑定参数。
  7. 在此之后,我希望你能用你的日常工作确定发生了什么,以什么顺序。

    在示例中'C:\Folder' | Set-ACLspecial 'Bob' ReadAndExecute 应将'Bob'分配给$Folder,因为位置在管道之前已绑定。