如何创建自定义Powershell运算符?

时间:2015-04-20 20:32:40

标签: powershell customization

是否可以在Powershell中创建自定义运算符?而且,我该怎么做?我搜索了谷歌,但没有任何事情发生。

我具体指的是中缀运营商:

$ ExampleList -contains " element"

我已经创建了cmdlet(包含Powershell和C#),模块等,所以我只需要广泛的笔触。

4 个答案:

答案 0 :(得分:9)

您可以创建前缀运算符,但不能创建in-fix或post-fix运算符,例如:

Set-Alias ?: Invoke-Ternary
function Invoke-Ternary {
param(
    [Parameter(Mandatory, Position=0)]
    [scriptblock]
    $Condition,

    [Parameter(Mandatory, Position=1)]
    [scriptblock]
    $TrueBlock,

    [Parameter(Mandatory, Position=2)]
    [scriptblock]
    $FalseBlock,

    [Parameter(ValueFromPipeline, ParameterSetName='InputObject')]
    [psobject]
    $InputObject
)

Process {
    if ($pscmdlet.ParameterSetName -eq 'InputObject') {
        Foreach-Object $Condition -input $InputObject | Foreach {
            if ($_) {
                Foreach-Object $TrueBlock -InputObject $InputObject
            }
            else {
                Foreach-Object $FalseBlock -InputObject $InputObject
            }
        }
    }
    elseif (&$Condition) {
        &$TrueBlock
    }
    else {
        &$FalseBlock
    }
}

像这样使用:

$toolPath = ?: {[IntPtr]::Size -eq 4} {"$env:ProgramFiles(x86)\Tools"} {"$env:ProgramFiles\Tools"}}

答案 1 :(得分:2)

我知道这对游戏来说已经很晚了......但是我觉得我会提供一个令人讨厌的黑客替代方案..唯一的好处就是做出一些东西"看起来"类似于C#操作符。

Set-Alias ?: Invoke-Ternary
function Invoke-Ternary {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [scriptblock]$Condition,
        [Parameter(Mandatory=$true, Position=0)]
        [scriptblock]$Expression
    )
    process {
        $TrueExpression = ($PSCmdlet.MyInvocation.BoundParameters['Expression'] -split '(?: +)?;(?: +)?')[0]
        $FalseExpression = ($PSCmdlet.MyInvocation.BoundParameters['Expression'] -split '(?: +)?;(?: +)?')[1]
        if (Invoke-Command -ScriptBlock $Condition) {
            Invoke-Command -ScriptBlock ([scriptblock]::Create($TrueExpression -replace '\{|\}'))
        } else {
            Invoke-Command -ScriptBlock ([scriptblock]::Create($FalseExpression -replace '\{|\}'))
        }
    }
}
{[IntPtr]::Size -eq 4} |?: {{'I like Soup'} ; {'I''d rather have toast'}}
{[IntPtr]::Size -eq 8} |?: {{'I like Soup'} ; {'I''d rather have toast'}}

虽然这只不过是用分号分隔的第一个表达式的字符串修改(支持冒号),但它说明有多种方法可以实现此行为。 所有人都说..我很乐意为其创建官方运营商 三元和Null-Coalescing运算符..虽然我在它...一个官方的Use-Object(使用语句(非指令))也会很好。在那之前,我将继续我的小黑客,但它很高兴做梦。

答案 2 :(得分:1)

在思考之后,这就是我想出来的:

不确定它是否比Jon Tirjan的

更好
function Op {
    Param (
        # this operator is the reverse of -contains
        [switch] $isIn,

        # this operator is just an example 
        [switch] $Plus
    )

    if ($isIn) {
        if ($args.Length -ne 2) {
            throw "Requires two arguments"
        }

        return ($args[1] -contains $args[0])
    }
    elseif ($Plus) {
        if ($args.Length -ne 2) {
            throw "Requires two arguments"
        }

        return ($args[0] + $args[1])
    }
}

使用示例:

PS> $ExampleList = @("alpha", "bravo", "charlie")

PS> Op "alpha" -isIn $ExampleList
True

PS> Op "delta" -isIn $ExampleList
False

PS> Write-Host ("Answer: " + (Op 5 -plus 7))
Answer: 12

答案 3 :(得分:0)

您可以创建一个cmdlet并将列表输入其中。 要评估列表,请务必使用End函数而不是ProcessProcess会自动迭代您不想要的集合。

你的脚本看起来像这样:

$ExampleList | Test-Contains "element"