对于C#/ Java程序员,PowerShell相当于“ .Single()”

时间:2019-04-11 18:56:42

标签: linq powershell

我正在为CI编写一些脚本,并且我注意到我在声明过滤器的唯一性方面做得不好。例如,一个脚本假定

$availableZip = $(Get-ChildItem -Path .\ -Filter "*SomeName*.zip" -Recurse).FullName

将提供一个唯一的条目,但可能不提供任何条目,也可能提供多个条目。

这当然可以通过一些If-Else检查在下游进行处理,但是我想做的就是优雅地将PowerShell推送给我,从而产生错误,例如

$availableZip = $(Get-ChildItem -Path .\ -Filter "*SomeName*.zip" -Recurse | Where -Single).FullName

使得Where -Single会抛出某种SetIsEmptyExceptionSetContainsMultipleElementsException,而所有PowerShell附件都专门指向此行,甚至可能包括重复的成员。

  

Where-Object:值包含多个元素,其中仅允许一个元素,   可用元素:firstDirectory \ SomeSoftware.zip,Other-SomeSoftware.zip   在C:\ Users \ geoff \ Code \ Project \ MyScript.ps1:33 char:73
  + ... ChildItem -Path。\ -Filter“ SomeSoftware .zip” -recurse |其中-Single).FullName
  + ~~~~~~~~
  + CategoryInfo:InvalidArgument:(:) [Get-ChildItem],SingletonSetContainsMultipleElementsException
  + FullyQualifiedErrorId:TooManyElements,Microsoft.PowerShell.Commands.WhereObjectCommand

我是否有内置的方法来执行此操作?有什么可以使用的PowerShell技巧,还是应该使用带有私有功能的小模块(如果可以的话,最优雅的实现是什么?)

2 个答案:

答案 0 :(得分:3)

您总是可以像下面那样使用Linq。我试图通过首先只获取zip文件夹的名称来使其更加高效。

[string[]]$zips = @(Get-ChildItem -Path .\ -Filter "*SomeName*.zip" -Recurse -Name)

[string]$availableZipName = [System.Linq.Enumerable]::Single($zips)

$availableZip = Get-ChildItem -Path $availableZipName -Recurse

下面,我将其放入函数中以便于使用。

function Get-AvailableZip (
    [ValidateScript({ Test-Path $_ })]
    [string]$Path,
    [ValidateNotNullOrEmpty()]
    [string]$Filter
)
{
    [string[]]$zips = @(Get-ChildItem -Path $Path -Filter $Filter -Recurse -Name);

    [string]$availableZipName

    $availableZip = $null

    try
    {
            $availableZipName = [System.Linq.Enumerable]::Single($zips)

            $availableZip = Get-ChildItem -Path "$Path\$availableZipName" -Recurse
    }
    catch [System.InvalidOperationException]
    {


        if ($_.Exception.Message -eq "Sequence contains more than one element")
        {
            Write-Error -Message ([Environment]::NewLine + $_.Exception.Message + [Environment]::NewLine + "Files Found:" + [Environment]::NewLine + [string]::Join([Environment]::NewLine, $zips)) -Category LimitsExceeded -Exception ($_.Exception)            
        }
        else
        {
            if ($_.Exception.Message -eq "Sequence contains no elements")
            {
                Write-Error -Message ([Environment]::NewLine + $_.Exception.Message) -Category ObjectNotFound -Exception ($_.Exception)
            }
            else
            {
                throw
            }
        }
    }

    return $availableZip;
}

用法:

Get-AvailableZip -Path ".\" -Filter "*SomeName*.zip"

答案 1 :(得分:1)

如果您要A.使用管道,则B.具有可重复使用的功能,而C.具有相当快的功能:

  function Where-SingleObject {
    param (
      [Parameter(Mandatory, ValueFromPipeline, HelpMessage='Data to process')]$InputObject
    )
    begin {
      $i = 0
    }
    process {
      if($i -eq 1) {
        throw "Error"
      }; $i++
    }
    end {
      return $InputObject
    }

  }

  (Get-ChildItem -Path '' -Filter '' -Recurse).FullName | Where-SingleObject

如果愿意,您可以删除Mandatory并为0添加自定义错误。