PowerShell inline If (IIf)

后端 未结 7 1827
独厮守ぢ
独厮守ぢ 2020-12-07 16:24

How do I create an a statement with an inline If (IIf, see also: Immediate if or ternary If) in PowerShell?

If you also think that this should be a native Po

相关标签:
7条回答
  • 2020-12-07 16:53
    Function Compare-InlineIf  
    {  
    [CmdletBinding()]  
        Param(  
            [Parameter(  
                position=0,  
                Mandatory=$false,  
                ValueFromPipeline=$false  
            )]  
            $Condition,  
            [Parameter(  
                position=1,  
                Mandatory=$false,  
                ValueFromPipeline=$false  
            )]  
            $IfTrue,  
            [Parameter(  
                position=2,  
                Mandatory=$false,  
                ValueFromPipeline=$false  
            )]  
            $IfFalse  
        )  
        Begin{  
            Function Usage  
            {  
                write-host @"  
    Syntax  
        Compare-InlineIF [[-Condition] <test>] [[-IfTrue] <String> or <ScriptBlock>]  
     [[-IfFalse] <String> or <ScriptBlock>]  
    Inputs  
        None  
        You cannot pipe objects to this cmdlet.  
    
    Outputs  
        Depending on the evaluation of the condition statement, will be either the IfTrue or IfFalse suplied parameter values  
    Examples  
       .Example 1: perform Compare-InlineIf :  
        PS C:\>Compare-InlineIf -Condition (6 -gt 5) -IfTrue "yes" -IfFalse "no"  
    
        yes
    
       .Example 2: perform IIF :  
        PS C:\>IIF (6 -gt 5) "yes" "no"  
    
        yes  
    
       .Example 3: perform IIF :  
        PS C:\>IIF `$object "`$true","`$false"  
    
        False  
    
       .Example 4: perform IIF :  
        `$object = Get-Item -ErrorAction SilentlyContinue "HKCU:\AppEvents\EventLabels\.Default\"  
        IIf `$object {`$_.GetValue("DispFilename")}  
    
        @mmres.dll,-5824  
    "@  
            }  
        }  
        Process{  
            IF($IfTrue.count -eq 2 -and -not($IfFalse)){  
                $IfFalse = $IfTrue[1]  
                $IfTrue = $IfTrue[0]  
            }elseif($iftrue.count -ge 3 -and -not($IfFalse)){  
                Usage  
                break  
            }  
            If ($Condition -IsNot "Boolean")  
            {  
                $_ = $Condition  
            } else {}  
            If ($Condition)  
            {  
                If ($IfTrue -is "ScriptBlock")  
                {  
                    &$IfTrue  
                }  
                Else  
                {  
                    $IfTrue  
                }  
            }  
            Else  
            {  
                If ($IfFalse -is "ScriptBlock")  
                {  
                    &$IfFalse  
                }  
                Else  
                {  
                    $IfFalse  
                }  
            }  
        }  
        End{}  
    }  
    Set-Alias -Name IIF -Value Compare-InlineIf  
    
    0 讨论(0)
  • 2020-12-07 16:56

    Powershell 7 allows ternary operators:

    $message = (Test-Path $path) ? "Path exists" : "Path not found"
    

    Earlier versions: PowerShell gives back values that haven't been assigned.

    $a = if ($condition) { $true } else { $false }
    

    Example:

    "The item is $(if ($price -gt 100) { 'expensive' } else { 'cheap' })"
    

    Let's try it out:

    $price = 150
    The item is expensive
    $price = 75
    The item is cheap
    
    0 讨论(0)
  • 2020-12-07 17:02
    'The condition is {0}.' -f ('false','true')[$condition]
    
    0 讨论(0)
  • 2020-12-07 17:05

    You can use the PowerShell’s native way:

    "The condition is " + (&{If($Condition) {"True"} Else {"False"}}) + "."
    

    But as this adds a lot of parenthesis and brackets to your syntax, you might consider the following (probably one of the smallest existing) CmdLet:

    Function IIf($If, $Right, $Wrong) {If ($If) {$Right} Else {$Wrong}}
    

    Which will simplify your command to:

    "The condition is " + (IIf $Condition "True" "False") + "."
    

    Added 2014-09-19:

    I have been using the IIf cmdlet now for a while, and I still think it will make syntaxes more readable in a lot of cases, but as I agree with Jason’s note about the unwanted side effect that both possible values will be evaluated even obviously only one value is used, I have changed the IIf cmdlet a bit:

    Function IIf($If, $IfTrue, $IfFalse) {
        If ($If) {If ($IfTrue -is "ScriptBlock") {&$IfTrue} Else {$IfTrue}}
        Else {If ($IfFalse -is "ScriptBlock") {&$IfFalse} Else {$IfFalse}}
    }
    

    Now you might add a ScriptBlock (surrounded by {}'s) instead of an object which will not be evaluated if it is not required as shown in this example:

    IIf $a {1/$a} NaN
    

    Or placed inline:

    "The multiplicative inverse of $a is $(IIf $a {1/$a} NaN)."
    

    In case $a has a value other than zero, the multiplicative inverse is returned; otherwise, it will return NaN (where the {1/$a} is not evaluated).

    Another nice example where it will make a quiet ambiguous syntax a lot simpler (especially in case you want to place it inline) is where you want to run a method on an object which could potentially be $Null.

    The native ‘If’ way to do this, would be something like this:

    If ($Object) {$a = $Object.Method()} Else {$a = $null}
    

    (Note that the Else part is often required in e.g. loops where you will need to reset $a.)

    With the IIf cmdlet it will look like this:

    $a = IIf $Object {$Object.Method()}
    

    (Note that if the $Object is $Null, $a will automatically be set to $Null if no $IfFalse value is supplied.)


    Added 2014-09-19:

    Minor change to the IIf cmdlet which now sets the current object ($_ or $PSItem):

    Function IIf($If, $Then, $Else) {
        If ($If -IsNot "Boolean") {$_ = $If}
        If ($If) {If ($Then -is "ScriptBlock") {&$Then} Else {$Then}}
        Else {If ($Else -is "ScriptBlock") {&$Else} Else {$Else}}
    }
    

    This means you can simplify a statement (the PowerShell way) with a method on an object that could potentially be $Null.

    The general syntax for this will now be $a = IIf $Object {$_.Method()}. A more common example will look something like:

    $VolatileEnvironment = Get-Item -ErrorAction SilentlyContinue "HKCU:\Volatile Environment"
    $UserName = IIf $VolatileEnvironment {$_.GetValue("UserName")}
    

    Note that the command $VolatileEnvironment.GetValue("UserName") will normally result in an "You cannot call a method on a null-valued expression." error if the concerned registry (HKCU:\Volatile Environment) doesn’t exist; where the command IIf $VolatileEnvironment {$_.GetValue("UserName")} will just return $Null.

    If the $If parameter is a condition (something like $Number -lt 5) or forced to a condition (with the [Bool] type), the IIf cmdlet won't overrule the current object, e.g.:

    $RegistryKeys | ForEach {
        $UserName = IIf ($Number -lt 5) {$_.GetValue("UserName")}
    }
    

    Or:

    $RegistryKeys | ForEach {
        $UserName = IIf [Bool]$VolatileEnvironment {$_.OtherMethod()}
    }
    

    Added 2020-03-20:

    Using the ternary operator syntax

    PowerShell 7.0 introduced a new syntax using the ternary operator. It follows the C# ternary operator syntax:

    The ternary operator behaves like the simplified if-else statement. The <condition> expression is evaluated and the result is converted to a boolean to determine which branch should be evaluated next:

    The <if-true> expression is executed if the <condition> expression is true The <if-false> expression is executed if the <condition> expression is false

    Example:

    "The multiplicative inverse of $a is $($a ? (& {1/$a}) : 'NaN')."
    
    0 讨论(0)
  • 2020-12-07 17:16

    PowerShell doesn't have support for inline ifs. You'll have to create your own function (as another answer suggests), or combine if/else statements on a single line (as another answer also suggests).

    0 讨论(0)
  • 2020-12-07 17:18

    From blog post DIY: Ternary operator:

    Relevant code:
    # —————————————————————————
    # Name:   Invoke-Ternary
    # Alias:  ?:
    # Author: Karl Prosser
    # Desc:   Similar to the C# ? : operator e.g. 
    #            _name = (value != null) ? String.Empty : value;
    # Usage:  1..10 | ?: {$_ -gt 5} {“Greater than 5;$_} {“Not greater than 5”;$_}
    # —————————————————————————
    set-alias ?: Invoke-Ternary -Option AllScope -Description “PSCX filter alias”
    filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse) 
    {
       if (&$decider) { 
          &$ifTrue
       } else { 
          &$ifFalse 
       }
    }
    

    And then you can use that like this:

    $total = ($quantity * $price ) * (?:  {$quantity -le 10} {.9} {.75})
    

    This is the closest variant I have seen so far.

    0 讨论(0)
提交回复
热议问题