To add to mclayton's helpful answer:
It is simpler to use a predefined [cultureinfo]
instance that uses the your currency format, such as en-US
(US-English) in the [decimal]::Parse()
call, in combination with C
, the currency format specifier.
@(
[pscustomobject] @{ Price='$414.50' },
[pscustomobject] @{ Price='99.02$' }
[pscustomobject] @{ Price='999.03' }
[pscustomobject] @{ Price='$5.04' }
) |
Sort-Object { [decimal]::Parse($_.Price, 'C', [cultureinfo] 'en-US') }
Output (correctly numerically sorted):
Price
-----
$5.04
99.02$
$414.50
999.03
Note:
As the sample input values show, there's some flexibility with respect to what input formats are accepted, such as a trailing $
, and a value without $_
.
If the current culture can be assumed to be en-US
(or a different culture that uses the same currency symbol and formatting, notably also the same decimal separator, .
), you can omit the [cultureinfo] 'en-US'
argument in the [decimal]::Parse()
call above - though for robustness I suggest keeping it.
As an aside: PowerShell's casts (which don't support currency values) always use the invariant culture with string operands, irrespective of the current culture. Thus, something like [decimal] '3.14'
is recognized even while a culture that uses ,
as the decimal separator is in effect.
While the invariant culture - whose purpose is to provide representations that aren't culture-dependent and remain stable over time - is based on the US-English culture, it can not be used here, because its currency symbol is ¤
; e.g., (9.99).ToString('C', [cultureinfo]::InvariantCulture)
yields ¤9.99
.
An input value that cannot be parsed as a currency causes an (effectively) non-terminating error,[1] and such values sort before the currency values.
- If you simply want to ignore non-conforming values, use
try { [decimal]::Parse(...) } catch { }
- If you want to abort processing on encountering non-confirming values pass
-ErrorAction Stop
to the Sort-Object
call.
[1] A .NET method call that fails causes a statement-terminating error, but since the error occurs in a script block (in the context of a calculated property), only the statement inside the script block is terminated, not the enclosing Sort-Object
call