tl;dr
The existing, helpful answers explain that 0E2D
is interpreted as a number literal, namely a decimal value in scientific (exponential) notation, typed as a [decimal]
, due to suffix D
(d
would work too, as type-specifier suffixes are generally case-insensitive).
Let me complement them by explaining why $args[0]
still showed the argument's original string representation, at least when used as-is.
In argument parsing mode, i.e when arguments are passed to command, simple string values (ones that contain neither spaces nor other shell metacharacters) need not be quoted.
This creates ambiguity, such as in the case at hand: is 0E2D
meant to be a number, or meant to be a string ('0E2D'
)?
PowerShell's parameter (argument) parser handles this ambiguity as follows:
if the unquoted argument can be parsed as a number, it is.
if so, and if the default stringification of the number doesn't equal the argument as specified, the number is wrapped in a (mostly invisible) [psobject]
instance that caches the original (string) representation, which can be recalled via .psobject.ToString()
if the unquoted argument binds to an explicitly declared typed parameter, the originally parsed form is ultimately irrelevant, but it does matter in unbound argument-passing, i.e. when arguments are passed positionally in the absence of predeclared parameters, via the automatic $args
variable.
Here's an explicit illustration using 1L
as a positional, unbound argument, which is parsed as [long]
value 1
, with the original representation, 1L
, cached in the [psobject]
wrapper:
PS> & { $args[0].ToString(), $args[0].psobject.ToString() } 1L
1 # default stringification of the [long] value that 1L was parsed as
1L # original representation
The default display representation implicitly calls .psobject.ToString()
:
PS> & { $args[0] } 1L
1L # original representation - even though it was parsed as [long]
This - commendably - also applies when passing the argument to external programs, as PowerShell should make no assumptions as to whether the argument represents a number or not - that is up the target program:
PS> cmd /c echo 1L
1L # original representation
Unfortunately, however - as your question shows - both Windows PowerShell and PowerShell (Core) as of v7.2.6 - are inconsistent with respect to when they honor the cached string representation:
& {
$args[0] # ditto for ($args[0])
$($args[0]) # ditto for @($args[0])
"$($args[0])"
} 1L
Arguably, all these commands should honor the original representation but only some of them do:
1L
1L
1
With 0E2D
as the argument, as in your question, the two PowerShell editions even exhibit differences: $($args[0])
prints 0
in Windows PowerShell vs. O2ED
in PowerShell (Core) 7.2.6.
Another inconsistency is that if you pass such an argument to -f
, the format operator, it is only the cached string representation that is ever honored, not the numeric type that the argument was actually parsed as:
PS> & { '{0:N1}' -f $args[0] } 1.234e0 # Argument is parsed as a [double]
1.234e0 # !! Formatting the [double] as a number with 1 decimal place failed.
However, this behavior was declared to be by design - see GitHub issue #17199.
0E2C
, PowerShell can't resolve it as a valid hex so, it will be passed as a string toWrite-Host
. – Emigrate