How to create a custom Powershell operator?

▼魔方 西西 提交于 2019-12-07 12:23:06

问题


Is it possible to create a custom operator in Powershell? And, how would I do that? I've searched Google but nothing is coming up.

I'm referring to specifically an infix operator:

$ExampleList -contains "element"

I've created cmdlets (with Powershell and C#), modules, etc., so I just need the broad strokes.


回答1:


You can create a prefix operator but not an in-fix or post-fix operator e.g.:

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
    }
}

Use like so:

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



回答2:


I know this is really late to the game.. but figured I would offer a nasty hack alternative.. The only benefit would be to make something that "looks" similar to the C# operator.

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'}}

While this is really nothing more than string mangling of the first expression separated by a semicolon (in favor of a colon), it illustrates that there are multiple ways to accomplish this behavior. That all being said.. I would LOVE to have official operators created for the Ternary and the Null-Coalescing operators.. While I am at it.. an official Use-Object (using statement (not directive)) would be nice as well. Until then I will continue with my little hacks, but its nice to dream.




回答3:


After thinking on it, this is what I came up with:

Not sure if it's a better answer than Jon Tirjan's

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])
    }
}

Example usage:

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



回答4:


You can create a cmdlet and pipe the list into it. For evaluating a list, be sure to use the End function instead of Process. Process will automatically iterate the collection, which you don't want here.

Your script would look something like this:

$ExampleList | Test-Contains "element"


来源:https://stackoverflow.com/questions/29757842/how-to-create-a-custom-powershell-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!