- Section
- Windows
- Updated
- 19 Aug 2026
- Examples
- 26
PowerShell is rarely the tool you would pick to do mathematics. But once a script is already counting
files, converting bytes into gigabytes, or averaging a column out of a CSV, shelling out to something
else for the arithmetic costs more than learning the handful of operators and [Math] methods that
cover the job.
TL;DR: $x = 3; $y = $x + 2; $y prints 5. There is no ** operator — exponentiation is
[Math]::Pow(2, 3).
👉 Examples below were run on PowerShell 7.4.2. Anything using
[Math]also works in Windows PowerShell 5.1, since both sit on the same .NET type.
Basic arithmetic operators
Addition, subtraction, multiplication, division and modulus use the operators you would expect:
$sum = 10 + 20
$difference = 30 - 15
$product = 5 * 3
$quotient = 25 / 5
$remainder = 7 % 3
Write-Host "Sum: $sum, Difference: $difference, Product: $product"
Write-Host "Quotient: $quotient, Remainder: $remainder"Sum: 30, Difference: 15, Product: 15
Quotient: 5, Remainder: 1++ and -- increment and decrement a variable by one, which is what you want for counters:
$count = 0
$count++
$count # 1
$count--
$count # 0The compound assignment operators +=, -=, *=, /= and %= apply an operation to a variable in
place:
$number = 5
$number += 10 # 15
$number -= 3 # 12
$number *= 2 # 24
$number /= 4 # 6
$number %= 3 # 0There is no **=, for the same reason there is no **. See the exponent section below.
Hex literals and size multipliers
Two shorthands save a lot of typing in system administration scripts. Hexadecimal literals are
written 0x… and behave like any other number, which is convenient when you are working from
registry DWORDs or Windows error codes:
0x10 + 0x05 # 21And KB, MB, GB, TB and PB are numeric multipliers built into the language, so you never
have to write out a power of 1024:
1GB # 1073741824
1GB / 1MB # 1024Division does not truncate
This is the part that catches people arriving from Bash. In Bash, $((10 / 4)) gives 2, because
arithmetic expansion is integer-only. PowerShell widens the result to a Double instead:
(25 / 5).GetType().Name # Int32
(10 / 4).GetType().Name # Double
10 / 4 # 2.5A division that comes out even stays an Int32; one that does not becomes a Double. The type of
the result depends on the values, not on the expression, which matters as soon as a later line does
something type-sensitive with it. If you want Bash-style truncation, cast it — but note that casting
to [int] rounds, it does not chop:
[int](10 / 3) # 3
[int](5 / 2) # 2 <- rounds to even, not 3
[int](7 / 2) # 4Porting a script the other way, or want the same ground covered for Bash? See Math Arithmetic: How To Do Calculation in Bash?.
Watch the left operand when a value came from text
PowerShell decides what an operator means from the type of the left operand, then coerces the right one to match. Numbers read out of a file, a registry key, or an API response arrive as strings, and the results then diverge sharply:
"10" + 2 # 102 (string concatenation)
2 + "10" # 12 (addition)
"10" * 2 # 1010 (string repeated)
2 * "10" # 20 (multiplication)Same two values, opposite results, decided by which side they sit on. Cast the parsed value before doing arithmetic with it and the ambiguity goes away:
$parsed = "10"
[int]$parsed + 2 # 12Exponents and square roots
PowerShell has no exponentiation operator. 2 ** 3 does not evaluate to 8, it fails to parse:
You must provide a value expression following the '*' operator.Use [Math]::Pow instead, and [Math]::Sqrt for square roots:
[Math]::Pow(2, 3) # 8
[Math]::Pow(2, 10) # 1024
[Math]::Sqrt(16) # 4[Math]::Pow always returns a Double, even when both arguments are whole numbers and the answer is
exact. Cast it if you need an integer back:
[int][Math]::Pow(2, 10) # 1024, as Int32👉
[Math]and[System.Math]are the same type.[Math] -eq [System.Math]returnsTrueand[Math].FullNameisSystem.Math— PowerShell resolves theSystem.prefix for you. The short form is what most scripts use, and it is what this post uses throughout.
Rounding, absolute values, and precision
[Math]::Round rounds to the nearest whole number, or to a given number of decimal places:
[Math]::Round(3.14) # 3
[Math]::Round(3.14159, 2) # 3.14
[Math]::Abs(-7) # 7
[Math]::Ceiling(2.1) # 3
[Math]::Floor(2.9) # 2The default rounding mode is the one that surprises people:
[Math]::Round(2.5) # 2
[Math]::Round(3.5) # 4.NET rounds halfway cases to the nearest even number, a convention known as banker’s rounding.
It avoids the upward bias you get from always pushing .5 away from zero, which matters once you are
summing thousands of rounded values. If you want the schoolbook behavior, ask for it explicitly:
[Math]::Round(2.5, [MidpointRounding]::AwayFromZero) # 3Anything reporting on money or quotas should either pick a mode deliberately or use [decimal],
because [double] carries the usual binary floating-point error:
$x = 0.1 + 0.2
$x # 0.3
$x -eq 0.3 # FalseThe shell prints 0.3 because it displays the shortest string that round-trips back to the stored
value, not the value itself. Ask for full precision and the gap shows up:
(0.1 + 0.2).ToString('G17') # 0.30000000000000004[decimal] is base-10 and does not have the problem:
([decimal]0.1 + [decimal]0.2) -eq [decimal]0.3 # True[decimal] is slower than [double] and covers a smaller range, which makes it the standard choice
for currency and quota reporting, and a poor one for scientific work.
Trigonometry and logarithms
The rest of the .NET Math surface is reachable the same way. The trigonometric methods take
radians, so degrees need converting first:
$pi = [Math]::PI
[Math]::Sin(30 * ($pi / 180)) # 0.5
[Math]::Cos(60 * ($pi / 180)) # 0.5
[Math]::Log(100, 10) # 2
[Math]::Log10(1000) # 3Expect floating-point residue on angles that should come out clean: [Math]::Sin($pi) evaluates to
1.22464679914735E-16. Compare trigonometric results against a tolerance rather than with -eq.
Random numbers
For random numbers PowerShell gives you a cmdlet, Get-Random:
Get-Random -Minimum 1 -Maximum 100 # e.g. 74-Maximum is exclusive, so that call returns 1 through 99. Get-Random also picks an element out of
a collection, which is often what you actually want:
Get-Random -InputObject @('web01', 'web02', 'web03')Doing math over a collection
Writing a loop to total a list is the long way round. Measure-Object takes a pipeline and returns
the aggregate:
1..10 | Measure-Object -Sum -Average -Maximum -MinimumCount : 10
Average : 5.5
Sum : 55
Maximum : 10
Minimum : 1
StandardDeviation :
Property :The empty StandardDeviation line is there because it was not asked for. Add -StandardDeviation,
or -AllStats for the lot.
With -Property it works against a field on an object, which is where it earns its place:
Get-ChildItem C:\logs | Measure-Object -Property Length -SumPull individual values back out with a subexpression:
$stats = Get-ChildItem C:\logs | Measure-Object -Property Length -Sum -Average
"Total: $([Math]::Round($stats.Sum / 1GB, 2)) GB across $($stats.Count) files"That covers the arithmetic most scripts need. For anything else, [Math] | Get-Member -Static lists
the whole type in the console, which usually answers the question faster than a search engine will.
