29

I'm trying to convert an argument of my PowerShell script to a boolean value. This line

[System.Convert]::ToBoolean($a)

works fine as long as I use valid values such as "true" or "false", but when an invalid value, such as "bla" or "" is passed, an error is returned. I need something akin to TryParse, that would just set the value to false if the input value is invalid and return a boolean indicating conversion success or failure. For the record, I tried [boolean]::TryParse and [bool]::TryParse, PowerShell doesn't seem to recognize it.

Right now I'm having to clumsily handle this by having two extra if statements.

What surprised me that none of the how-to's and blog posts I've found so far deal with invalid values. Am I missing something or are the PowerShell kids simply too cool for input validation?

wonea
  • 4,783
  • 17
  • 86
  • 139
Shaggydog
  • 3,456
  • 7
  • 33
  • 50
  • 3
    You can specify parameter types in your script arguments, like `[bool]$something`. This way data types will be validated before your script even starts working. – Victor Zakharov Dec 15 '14 at 13:58
  • Powershell has all kinds of options for validating parameter input so that you don't have to do it your self. http://technet.microsoft.com/en-us/library/hh847743.aspx Powershell will even generate good enough localized error messages for you. This info gets used in the get-help command too. – kevmar Dec 16 '14 at 04:33
  • Have you considered using a `[switch]` parameter? See the Switch Parameter section in [`Get-Help about_Functions`](http://go.microsoft.com/fwlink/?LinkID=113231). – Emperor XLII Dec 18 '14 at 00:39

6 Answers6

31

You could use a try / catch block:

$a = "bla"
try {
  $result = [System.Convert]::ToBoolean($a) 
} catch [FormatException] {
  $result = $false
}

Gives:

> $result
False
arco444
  • 22,002
  • 12
  • 63
  • 67
29

TryParse should work as long as you use ref and declare the variable first:

$out = $null
if ([bool]::TryParse($a, [ref]$out)) {
    # parsed to a boolean
    Write-Host "Value: $out"
} else {
    Write-Host "Input is not boolean: $a"
}
Emperor XLII
  • 13,014
  • 11
  • 65
  • 75
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
9
$a = 'bla'
$a = ($a -eq [bool]::TrueString).tostring()
$a

False
mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • This is because PowerShell will convert any string greater than 0 characters to a Boolean ‘true’, behaviour which is consistent across other programming languages. – Oliver Nilsen Aug 11 '23 at 10:19
3

Another possibility is to use the switch statemement and only evaluate True, 1 and default:

$a = "Bla"
$ret = switch ($a) { {$_ -eq 1 -or $_ -eq  "True"}{$True} default{$false}}

In this if the string equals to True $true is returned. In all other cases $false is returned.

And another way to do it is this:

@{$true="True";$false="False"}[$a -eq "True" -or $a -eq 1]

Source Ternary operator in PowerShell by Jon Friesen

Micky Balladelli
  • 9,781
  • 2
  • 33
  • 31
  • I just used this to include integer and string values.. ``Function ParseBool{ [CmdletBinding()] param( [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String]$inputVal ) switch -regex ($inputVal) { "^1$|^true$" {$true} default{$false} } }`` – David Wallis Dec 19 '16 at 14:38
2

just looked for this again and found my own answer - but as a comment so adding as an answer with a few corrections / other input values and also a pester test to verify it works as expected:

Function ParseBool{
    [CmdletBinding()]
    param(
        [Parameter(Position=0)]
        [System.String]$inputVal
    )
    switch -regex ($inputVal.Trim())
    {
        "^(1|true|yes|on|enabled)$" { $true }

        default { $false }
    }
}

Describe "ParseBool Testing" {
    $testcases = @(
        @{ TestValue = '1'; Expected = $true },
        @{ TestValue = ' true'; Expected = $true },
        @{ TestValue = 'true '; Expected = $true },
        @{ TestValue = 'true'; Expected = $true },
        @{ TestValue = 'True'; Expected = $true },
        @{ TestValue = 'yes'; Expected = $true },
        @{ TestValue = 'Yes'; Expected = $true },
        @{ TestValue = 'on'; Expected = $true },
        @{ TestValue = 'On'; Expected = $true },
        @{ TestValue = 'enabled'; Expected = $true },
        @{ TestValue = 'Enabled'; Expected = $true },

        @{ TestValue = $null; Expected = $false },
        @{ TestValue = ''; Expected = $false },
        @{ TestValue = '0'; Expected = $false },
        @{ TestValue = ' false'; Expected = $false },
        @{ TestValue = 'false '; Expected = $false },
        @{ TestValue = 'false'; Expected = $false },
        @{ TestValue = 'False'; Expected = $false },
        @{ TestValue = 'no'; Expected = $false },
        @{ TestValue = 'No'; Expected = $false },
        @{ TestValue = 'off'; Expected = $false },
        @{ TestValue = 'Off'; Expected = $false },
        @{ TestValue = 'disabled'; Expected = $false },
        @{ TestValue = 'Disabled'; Expected = $false }
    )


    It 'input <TestValue> parses as <Expected>' -TestCases $testCases {
        param ($TestValue, $Expected)
        ParseBool $TestValue | Should Be $Expected
    }
}
David Wallis
  • 185
  • 11
1

Prior answers are more complete, but if you know that $foo -eq 1, "1", 0, "0", $true, $false... anything that can be coerced to an [int]

Either of the following statements work:

[System.Convert]::ToBoolean([int]$foo)
[System.Convert]::ToBoolean(0 + $foo)

Hope that helps someone that just needs a simple solution.

Anas Mehar
  • 2,739
  • 14
  • 25