How to create a custom Powershell operator?
You can create a prefix operator but not an in-fix or post-fix operator e.g.:
Set-Alias ?: Invoke-Ternaryfunction 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"}}
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 $ExampleListTruePS> Op "delta" -isIn $ExampleListFalsePS> Write-Host ("Answer: " + (Op 5 -plus 7))Answer: 12
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 { [cmdletbinding()] param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [object]$Condition, [Parameter(Mandatory=$true, Position=0)] [Alias('FirstExpression')] [object]$Consequent, [Parameter(Mandatory=$true, Position=1)] [Alias('SecondExpression')] [object]$Alternative ) $isTrue = if($Condition.GetType().Name -eq 'Scriptblock'){ Invoke-Command -ScriptBlock $Condition } else { $Condition } if ($isTrue) { if($Consequent.GetType().Name -eq 'Scriptblock'){ Invoke-Command -ScriptBlock $Consequent } else { $Consequent } } else { if($Alternative.GetType().Name -eq 'Scriptblock'){ Invoke-Command -ScriptBlock $Alternative } else { $Alternative } } } {[IntPtr]::Size -eq 4} |?: 'I like Soup' {'test'|?: 3 ('{0} prefer toast' -f 'We')} {[IntPtr]::Size -eq 8} |?: 'I like Soup' {$false|?: 3 ('{0} prefer toast' -f 'We')}
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 forthe 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.