1

I have the following number of type System.UInt32: 4.294.967.176 (in bytes: FFFF FF88).

I have to interpret this number as a number of type System.Int32, where it will be: -120 (in bytes still: FFFF FF88).

In languages like C or C++ a simple type cast would solve my problem, but type casting in PowerShell:

[Int32][UInt32]4294967176

throws an error:

Cannot convert value "4294967176" to type "System.Int32". Error: "Value was either too large or too small for an
Int32."
At line:1 char:1
+ [Int32][UInt32]4294967176
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastIConvertible

It looks like PowerShell is trying to "convert" the value instead of just casting it. So, how do I cast System.UInt32 to System.Int32, meaning not changing the data, but using another interpretation/representation?

stackprotector
  • 10,498
  • 4
  • 35
  • 64
  • 2
    4294967178 is actually 0xFFFFFF8A or -118 when interpreted in two's complement. Without compiling actual C#, one way of doing it (which literally reinterprets the data) is `[BitConverter]::ToInt32([BitConverter]::GetBytes([uint32] 4294967178))`. There may be a shorter way by exploiting some method somewhere that I don't know about; on the runtime level this cast is a single instruction, but I don't think there's a direct code path for it in PowerShell. – Jeroen Mostert Aug 18 '20 at 08:25
  • 1
    @JeroenMostert The last digit was a typo, I corrected it. Your solution works, when adding 0 as the second parameter of ToInt32 (as start index). Thank you! – stackprotector Aug 18 '20 at 09:10

2 Answers2

3

Since .Net numeric data types support conversion into hex equivalents, convert the UInt32 into string first. Then use System.Convert.ToInt32() and parse hex to int. Like so,

$u = [UInt32]4294967176
$u.tostring('x')
ffffff88

# Convert hex based value to int
$i =  [convert]::toint32($u.tostring('x'), 16) 

# Check that type is int32
$i.GetType()
IsPublic IsSerial Name                             BaseType
-------- -------- ----                             --------
True     True     Int32                            System.ValueType

# Value    
$i
-120
stackprotector
  • 10,498
  • 4
  • 35
  • 64
vonPryz
  • 22,996
  • 7
  • 54
  • 65
  • 1
    The solution from the [comments](https://stackoverflow.com/questions/63464374/how-to-cast-an-uint32-to-a-negative-int32-in-powershell?noredirect=1#comment112224714_63464374) is slightly faster, but not that much that it would matter imo. Code for comparison: `$u = [System.UInt32] 4294967176; (Measure-Command {1..100000 | % {[System.Convert]::ToInt32($u.ToString('x'), 16)}}).Ticks; (Measure-Command {1..100000 | % {[System.BitConverter]::ToInt32([System.BitConverter]::GetBytes($u), 0)}}).Ticks` – stackprotector Aug 18 '20 at 10:06
0

No need for any string-operations. Just use the bitconverter-functions:

$u   = [UInt32]4294967176
$arr = [bitconverter]::GetBytes($u)
[bitconverter]::ToInt32($arr,0)
Carsten
  • 1,612
  • 14
  • 21