6

PowerShell seems to perform bounds-checking after arithmetic operations and conversions. For instance, the following operations fail:

[byte]$a = 255
$a++

$a = [byte]256

Is there any way to enforce overflows or the typecast without resorting to a manual calculation via modulo or C# and Add-Type?

Chrysler
  • 91
  • 3
  • 1
    The operations fail, because you explicitly cast a type and try to assign a value that's too big for this type. This behavior is by design. What should PowerShell do in case of an overflow? Cut the value off at MAXVALUE? Wrap the value with a modulo operation? Assign the overflowing value to a new variable? PowerShell can't possibly guess what would be the correct way to handle an overflow in your particular situation, so throwing an error is the only reasonable thing to do. – Ansgar Wiechers Mar 30 '13 at 20:35
  • 2
    As I said I am looking for the behaviour of most other (all?) programming languages that perform no overflow checks: a modulo operation. Many encryption and hash algorithms rely on this so it would make perfectly sense if PowerShell supported it. – Chrysler Mar 30 '13 at 23:15
  • Of course PowerShell supports modulo operations. It just doesn't make blind guesses as to what would be "the obvious thing" you want it to do right now. If you want a modulo operation: apply a modulo operation. Problem solved. – Ansgar Wiechers Mar 30 '13 at 23:19
  • I meant an implicit modulo operation when values leave the data type value range. I know it's possible to simulate it with the modulo operator but that makes the code really hard to read. I am writing a C# to PowerShell converter and cannot translate every "a++" in C# to "$a = [UInt32](($a + 1) % ([UInt32]::MaxValue + 1))". But that is actually the only way to correctly express the behaviour of the C# code, assuming there is no proper support for this in PowerShell. – Chrysler Mar 30 '13 at 23:37
  • 1
    Guys, calm down. He's just looking for regular binary int and byte behavior. -- As opposed to the bounds checking you get from .NET and C#. -- In C# you can suppress bounds checking with the `unchecked` keyword. -- So, clearly, .NET can do this. -- So, what's the equivalent for PowerShell? – BrainSlugs83 May 17 '17 at 03:05

2 Answers2

4

The behavior you want in PowerShell is achievable, though, it's a bit of a hack; and maybe there's a better way.

If you just want cryptographic functionality though, it's worth calling out, that there's a TON of that already built-in to the BCL, and it's fully accessible from PowerShell (MD5, SHA, RSA, X509, a ton of other stuff too).

But if you're dead set on performing unchecked arithmetic in PowerShell, this is a hack that should give you what you want (basically we're embedding C# code, and using the unchecked keyword):

$members = @' 
public static UInt32 ToUInt32(int value)
{
    unchecked
    {
        return (UInt32)value;
    }
}


public static byte ToByte(int value)
{
    unchecked
    {
        return (byte)value;
    }
}
'@;

$type = Add-Type -Name "Convert" -Namespace "Helpers" `
        -MemberDefinition $members -PassThru -ErrorAction SilentlyContinue;

Usage:

PS C:\Some\Folder> [Helpers.Convert]::ToUInt32(-1);
4294967295

PS C:\Some\Folder> [Helpers.Convert]::ToByte(-1);
255

PS C:\Some\Folder> [Helpers.Convert]::ToByte(256);
0

Of Note:

  • We're calling [Helpers.Convert]::To... and not [System.Convert]::To....
  • If you need other methods, the actual C# methods will need to be inserted into the $members block at the top of the code.
  • If you run Add-Type multiple times in a row for the same Namespace and Name combination, in the same PowerShell session, it will fail; and you will be left with the previously registered type. -- I've added -ErrorAction SilentlyContinue to ignore this specific scenario. -- That way, you can dump this code into a .ps1 script, and call it every single time, before you use them methods, and they will always be present. -- But if you are modifying the C# code and retesting, you will want to change the type name after every change you make; it's kind of painful.
BrainSlugs83
  • 5,517
  • 5
  • 45
  • 51
  • Nicely done. However, note that running `Add-Type` repeatedly without changes is (conveniently) a _quiet no-op_. Only if you try to _redefine_ the type by modifying the value of `$members` do you get an error; not only do you _not_ want to ignore this error, `-ErrorAction SilentlyContinue` is ineffective in doing so, because the error is a statement-_terminating_ one. – mklement0 May 08 '19 at 17:13
  • In C#, you would usually use the keyword `uint` instead of the framework type name `UInt32`. – Jeppe Stig Nielsen Dec 18 '20 at 08:41
1

PowerShell is a scripting language, not a programming language, it doesn't support a lot of advanced techniques like overloading operators (which would be handy in this case).

To add to the things you have already suggested, you could just catch the error.

[byte]$a = 255
try {$a++} catch {$a=1}

Or write your own function and do some modulo fun in there.

Neossian
  • 636
  • 4
  • 12