49

In PowerShell, how can I test if a variable holds a numeric value?

Currently, I'm trying to do it like this, but it always seems to return false.

add-type -Language CSharpVersion3 @'
    public class Helpers {
        public static bool IsNumeric(object o) {
            return o is byte  || o is short  || o is int  || o is long
                || o is sbyte || o is ushort || o is uint || o is ulong
                || o is float || o is double || o is decimal
                ;
        }
    }
'@

filter isNumeric($InputObject) {
    [Helpers]::IsNumeric($InputObject)
}

PS> 1 | isNumeric
False
1
  • 1
    Use isNumeric -InputObject 1 instead of piping Commented Dec 21, 2024 at 1:14

15 Answers 15

64

You can check whether the variable is a number like this: $val -is [int]

This will work for numeric values, but not if the number is wrapped in quotes:

1 -is [int]
True
"1" -is [int]
False
Sign up to request clarification or add additional context in comments.

3 Comments

@Christian you're right. I was only thinking about the case in the question.
@CB that's because 1.5 is not an integer, it is a double... 1.5 -is [double] evaluates to true
Also fails if the value is cast as a Int64.
45

If you are testing a string for a numeric value then you can use the a regular expression and the -match comparison. Otherwise Christian's answer is a good solution for type checking.

function Is-Numeric ($Value) {
    return $Value -match "^[\d\.]+$"
}

Is-Numeric 1.23
True
Is-Numeric 123
True
Is-Numeric ""
False
Is-Numeric "asdf123"
False

5 Comments

I'm not testing a string, I'm testing a type. But ignoring that for the moment, how about negative values? And what about exponential values (3.24643e4)? Yeah, I know, I'm splitting hairs!
I'll leave that as an exercise for the reader. :) I just wanted to add this for people who may stumble on the question looking for checking numeric string values.
Well done @silent__thought, I was looking for exactly this.
"1.2.3" -match "^[\d\.]+$" --> True. "^(\d+|\.\d+|\d+\.\d+)$" would allow only one decimal separator. Returns true for "1", ".1", "1.1" and false for "1.", "1.1.1", "".
this regex is incorrect, Is-Numeric ................. would be true
38

You can do something like :

$testvar -match '^[0-9]+$'

or

$testvar -match '^\d+$'

Returns True if $testvar is a number.

3 Comments

This will only return true for positive integers
Check it '00:03:34,00 --> 00:03:36,80' -match '[0-9]+$' 5 -match '[0-9]+$'
@Garric That's because you missed the '^'. The regexmeans start of string, then one or more digits/dots, then end of string. Without it, it matches the "80" at the end yes.
34

Modify your filter like this:

filter isNumeric {
    [Helpers]::IsNumeric($_)
}

function uses the $input variable to contain pipeline information whereas the filter uses the special variable $_ that contains the current pipeline object.

Edit:

For a powershell syntax way you can use just a filter (w/o add-type):

filter isNumeric($x) {
    return $x -is [byte]  -or $x -is [int16]  -or $x -is [int32]  -or $x -is [int64]  `
       -or $x -is [sbyte] -or $x -is [uint16] -or $x -is [uint32] -or $x -is [uint64] `
       -or $x -is [float] -or $x -is [double] -or $x -is [decimal]
}

3 Comments

I think the native PowerShell route is the way I'll go. Thanks, @Christian.
Unable to find type [Helpers]
This is the first answer that really tests if a variable holds a numeric value. All others test if a string represents a numeric value
18

If you want to check if a string has a numeric value, use this code:

$a = "44.4"
$b = "ad"
$rtn = ""
[double]::TryParse($a,[ref]$rtn)
[double]::TryParse($b,[ref]$rtn)

Credits go here

Comments

14
PS> Add-Type -Assembly Microsoft.VisualBasic
PS> [Microsoft.VisualBasic.Information]::IsNumeric(1.5)
True

http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.information.isnumeric.aspx

1 Comment

I thought this was pretty neat until I realised that it would return true for a string that was numeric such as "1.23" which is not what I want. I want to know if the type of the actual object is a numeric type, not whether or not it can be coerced to a numeric type. Thanks for a useful tip though, I can see where that will be very handy.
11

-is and -as operators requires a type you can compare against. If you're not sure what the type might be, try to evaluate the content (partial type list):

(Invoke-Expression '1.5').GetType().Name -match 'byte|short|int32|long|sbyte|ushort|uint32|ulong|float|double|decimal'

Good or bad, it can work against hex values as well (Invoke-Expression '0xA' ...)

2 Comments

That's a neat solution. For the context I need to use it though, Invoke-Expression could be quite dodgy!
Try{(Invoke-Expression '-123s.456e-789 ').GetType().Name -match 'byte|short|int32|long|sbyte|ushort|uint32|ulong|float|double|decimal'}Catch{$false}---Although you solution is almost perfect and flexible
7
filter isNumeric {
    $_ -is [ValueType]
}

-

1 -is [ValueType]
True
"1" -is [ValueType]
False

-

function isNumeric ($Value) {
    return $Value -is [ValueType]
}

isNumeric 1.23
True
isNumeric 123
True
isNumeric ""
False
isNumeric "asdf123"
False

-

(Invoke-Expression '1.5') -is [ValueType]

5 Comments

PS> [System.Reflection.BindingFlags]::CreateInstance -is [valuetype] (True)
PS> [char]"a" -is [valuetype] (True)
This is the right answer!
@x0n I don't know why but although your tests are ... true the function isNumeric correctly returns $false for both your cases. VERY strange but I'm also very tired.
This is by far the best and most succinct PowerShell solution. Nicely done!
4
$itisint=$true
try{
 [int]$vartotest
}catch{
 "error converting to int"
 $itisint=$false
}

this is more universal, because this way you can test also strings (read from a file for example) if they represent number. The other solutions using -is [int] result in false if you would have "123" as string in a variable. This also works on machines with older powershell then 5.1

2 Comments

It’s always valuable to explain your code, but that’s especially true in a case like this where there’s a highly-rated accepted answer from eight years ago. Why is your approach preferred over the accepted answer? Do you mind updating your answer with more details?
If you are using Read-Host the result is always a string so you need to perform a check to see if the input even is numeric before converting. Generating and catching exceptions as flow control is always bad due to the amount of stuff done behind the scenes. The powershell way would be $converted = $myInput -as [int]. $converted will be $null if it could not convert, or the number if it was successful
3

Thank you all who contributed to this thread and helped me figure out how to test for numeric values. I wanted to post my results for how to handle negative numbers, for those who may also find this thread when searching...

Note: My function requires a string to be passed, due to using Trim().

function IsNumeric($value) {
# This function will test if a string value is numeric
#
# Parameters::
#
#   $value   - String to test
#
   return ($($value.Trim()) -match "^[-]?[0-9.]+$")
}

1 Comment

This will return true for version numbers like "9.3.4", you'd be better served by a regex like ^[-+]?([0-9]*\.[0-9]+|[0-9]+\.?)$ which will validate you have only an optional plus/minus; numbers and an single optional decimal point.
3

If you know the numeric type you want to test against (such as int for example in the code below), you can do it like this:

> [bool]("42" -as [int])
True
> [bool](42 -as [int])
True
> [bool]("hi" -as [int])
False

But note:

> [bool]("42.1" -as [int])
True

Careful!:

It was pointed out that the code above fails to identify 0 as an int. You would need to add a guard for 0:

> $n -eq 0 -or $n -as [int]

Where $n is the object you are testing.

6 Comments

I like this one. Or '11' | where { $(if ($_ -as 'int') { 10 -le $_ }) }
Unfortunately: [bool](0 -as [int]) is False.
@HankSchultz thanks. That is a good bug to find. I have added a note at the end.
@dan-gph, to be clear, it isn't failing to recognize 0 as an int. Instead, it's casting 0 to False.
[bool]("42.1" -as [int]) return True as well.
|
2

I ran into this topic while working on input validation with read-host. If I tried to specify the data type for the variable as part of the read-host command and the user entered something other than that data type then read-host would error out. This is how I got around that and ensured that the user enters the data type I wanted:

do
    {
    try
        {
        [int]$thing = read-host -prompt "Enter a number or else"
        $GotANumber = $true
        }
    catch
        {
        $GotANumber = $false
        }
    }
until
    ($gotanumber)

Comments

2

Each numeric type has its own value. See TypeCode enum definition: https://learn.microsoft.com/en-us/dotnet/api/system.typecode?view=netframework-4.8 Based on this info, all your numeric type-values are in the range from 5 to 15. This means, you can write the condition-check like this:

$typeValue = $x.getTypeCode().value__
if ($typeValue -ge 5 -and $typeValue -le 15) {"x has a numeric type!"}

Comments

1
"-123.456e-789" -match "^\-?(\d+\.?\d*)(e\-?\d+)?$|^0x[0-9a-f]+$"

or

"0xab789" -match "^\-?(\d+\.?\d*)(e\-?\d+)?$|^0x[0-9a-f]+$"

will check for numbers (integers, floats and hex).

Please note that this does not cover the case of commas/dots being used as separators for thousands.

Comments

0

Testing if a value is numeric or a string representation of a numeric value.

function Test-Number 
{
    Param
    (
        [Parameter(Mandatory=$true,
                   Position=0)]
        [ValidatePattern("^[\d\.]+$")]
        $Number
    )

    $Number -is [ValueType] -or [Double]::TryParse($Number,[ref]$null)
}

Testing if a value is numeric.

function Test-Number 
{
    Param
    (
        [Parameter(Mandatory=$true,
                   Position=0)]
        [ValidatePattern("^[\d\.]+$")]
        $Number
    )

    $Number -is [ValueType]
}

1 Comment

$n=0; [Double]::TryParse('1e2', [ref]$n) will parse it as a string representation of a number, but your functions will fail it. Same with negative numbers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.