【问题标题】:powershell v7 - Function pipeline issuepowershell v7 - 功能管道问题
【发布时间】:2021-06-06 08:11:42
【问题描述】:

我正在尝试编写 2 个函数:

  • 第一个 (Get-Lab) 检索 [Lab] 对象
  • 第二个(remove-Lab)删除一个 [Lab] 对象

[Lab] 是我的模块中定义的一个类。

当运行 Get-Lab 时,我使用正确的类型正确检索了我的实验室实例:

当我运行 Remove-Lab -Lab (Get-Lab -Name Mylab) 时,操作正确执行:

但是当我尝试通过管道传递 [Lab] 对象时它失败了。

函数没有通过管道接收对象。但是,我使用 ValueFromPipeline=$true 将 -Lab 参数设置为强制。

Function Remove-Lab{
[CmdletBinding(DefaultParameterSetName='Lab')]
param (
    [Parameter(ValueFromPipeline=$true,ParameterSetName='Lab',Position=0,Mandatory=$true)]
    [Lab]
    $Lab,
    
    # Parameter help description
    [Parameter(Position=1,Mandatory=$false)]
    [switch]
    $Force=$false
)

begin {
    Write-host ("`tLabName : {0}" -f $Lab.Name) -ForegroundColor Yellow

    if ($null -ne $Lab) {
        $LabToRemove = $Lab
    }

    if (-not [string]::IsNullOrEmpty($LabId)) {
        $LabToRemove = Get-Lab -Id $LabId
    }

    if (-not [string]::IsNullOrEmpty($Name)) {
        $LabToRemove = Get-Lab -Name $Name
    }

    if ($null -eq $LabToRemove) {
        throw "There is no Lab with specified characteristics. Please check your input"
    }
}

process {
    $DoRemoval = $true
    if ($Force.IsPresent -eq $false) {
        while ($null -eq $UserInput -or $UserInput -notin @('Y','N')) {
            $UserInput = Read-HostDefault -Prompt "Are you sure want to remove the selected Lab and all its components ? [Y]es, [N]o" -Default 'N'

            if ($UserInput -eq 'N') {
                $DoRemoval = $false
            }
        }

        Write-Host ("`tUser Input : {0}" -f $UserInput) -ForegroundColor Green
    }

    if ($DoRemoval -eq $true) {
        Write-Host ("`tAbout to Remove the following Lab : {0}" -f $LabToRemove.Name) -ForegroundColor Green
    }
}

end {

}

}

正如您在下面调试此函数时看到的,$Lab 参数为空。

你对这个问题有什么想法吗?

【问题讨论】:

  • 可能很傻,但是您是否尝试将Get-Lab 的值添加到变量并将该变量传递给Remove-Lab。老实说,我自己从来没有做过,但也许你的Get-Lab 函数不是'pipable'。
  • 您无法访问begin 中的管道输入,$Lab 在到达process 块之前将不可用
  • @Alex_P :已经尝试过但不是解决方案。解决方案由 Matthias 提出

标签: powershell


【解决方案1】:

由于函数正在$LabId$Name 上进行测试,因此这些变量需要存在于函数中,而目前它们不存在。 尝试将参数更改为:

[CmdletBinding(DefaultParameterSetName='LabId')]
param (
    [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName='LabId',Position=0,Mandatory=$true)]
    [string]$LabId,

    [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName='LabName',Position=0,Mandatory=$true)]
    [string]$Name,

    # Parameter help description
    [switch]$Force  # no need to set a switch to $false because if you don't send that param, the undelying value will be $false by default
)

然后删除

Write-host ("`tLabName : {0}" -f $Lab.Name) -ForegroundColor Yellow

if ($null -ne $Lab) {
    $LabToRemove = $Lab
}

这里的重要部分是ValueFromPipelineByPropertyName = $true 声明

【讨论】:

    【解决方案2】:

    begin 在其他任何事情之前运行,包括管道参数绑定 - 因此您需要将检查管道绑定参数(如 $Lab)的代码移动到 process 块:

    Function Remove-Lab{
    [CmdletBinding(DefaultParameterSetName='Lab')]
    param (
        [Parameter(ValueFromPipeline=$true,ParameterSetName='Lab',Position=0,Mandatory=$true)]
        [Lab]
        $Lab,
        
        # Parameter help description
        [Parameter(Position=1,Mandatory=$false)]
        [switch]
        $Force=$false
    )
    
    process {
        Write-host ("`tLabName : {0}" -f $Lab.Name) -ForegroundColor Yellow
    
        if ($null -ne $Lab) {
            $LabToRemove = $Lab
        }
    
        if (-not [string]::IsNullOrEmpty($LabId)) {
            $LabToRemove = Get-Lab -Id $LabId
        }
    
        if (-not [string]::IsNullOrEmpty($Name)) {
            $LabToRemove = Get-Lab -Name $Name
        }
    
        if ($null -eq $LabToRemove) {
            throw "There is no Lab with specified characteristics. Please check your input"
        }
    
        $DoRemoval = $true
        if ($Force.IsPresent -eq $false) {
            while ($null -eq $UserInput -or $UserInput -notin @('Y','N')) {
                $UserInput = Read-HostDefault -Prompt "Are you sure want to remove the selected Lab and all its components ? [Y]es, [N]o" -Default 'N'
    
                if ($UserInput -eq 'N') {
                    $DoRemoval = $false
                }
            }
    
            Write-Host ("`tUser Input : {0}" -f $UserInput) -ForegroundColor Green
        }
    
        if ($DoRemoval -eq $true) {
            Write-Host ("`tAbout to Remove the following Lab : {0}" -f $LabToRemove.Name) -ForegroundColor Green
        }
    }
    

    【讨论】:

    • 非常感谢您的快速回答。通过在流程块中移动参数检查,它可以工作。
    • @Régis 不客气!注意Theo's answer as well - 如果你想回退到$Name$LabId,你应该用单独的参数集名称声明它们
    • @Régis 还有一件事:在管道中间直接调用阻塞输入函数(如 Read-HostDefault)通常是个坏主意 - 如果需要,请实现适当的 ShouldProcess 和确认影响支持像这样:-)
    • 好的。感谢您的建议。我将仔细阅读您的链接。再见;-)
    猜你喜欢
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多