66

In PowerShell, I want to use New-Object to call a single-argument .Net constructor new X509Certificate2(byte[] byteArray). The problem is when I do this with a byte array from powershell, I get

New-Object : Cannot find an overload for "X509Certificate2" and the argument count: "516".

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
Tim Lovell-Smith
  • 15,310
  • 14
  • 76
  • 93

2 Answers2

79

This approach to using new-object should work:

$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate `
      -ArgumentList @(,$bytes)

The trick is that PowerShell is expecting an array of constructor arguments. When there is only one argument and it is an array, it can confuse PowerShell's overload resolution algorithm. The code above helps it out by putting the byte array in an array with just that one element.

Update: in PowerShell >= v5 you can call the constructor directly like so:

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate]::new($bytes)
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 2
    Two quibbles (and that's all they are): `(, $bytes)` is sufficient to construct the array; while `@(...)` ultimately works the same, it is not necessary and less efficient, because it constructs _another_ array (though in practice that will hardly matter). It is not the the constructor-overload resolution that's the problem, but PowerShell's standard _parameter binding_: `-ArgumentList` is `[object[]]`-typed, so if you pass a single argument that is an array (or similar), that array's elements become _individual_ arguments to pass to the constructor; the extra array wrapper avoids that. – mklement0 Nov 09 '18 at 16:02
  • Neither of these constructs is working for me on PS version 5.0 on a Win7 client. The first (w or w/o @) throws `Exception calling ".ctor" with 1 argument(s): "Cannot find the requested object." ` As if it's still trying to open a file name. The second throws: `Cannot find type[[System.Security.Cryptography.X509Certificates.X509Certificate]::new] verify that an assembly containing this type is loaded.` – DaveM Oct 15 '19 at 21:34
  • 1
    Okay, i figured it out. The cert data was corrupted...evidently those are the errors you get. Once I fixed that problem the form without the @ worked fine. – DaveM Oct 17 '19 at 03:33
10

Surprisingly to me, I tried this and it seems it works:

[byte[]] $certPublicBytes = something
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate] $certPublicBytes
return $cert

I don't yet know by what magic it works, so your explanatory comments are appreciated. :)

(Note: I since found that using square-brackets-type-name as I did above, can also lead to other errors, such as 'Cannot convert value "System.Byte[]" to type "System.Security.Cryptography.X509Certificates.X509Certificate". Error: "Cannot find the requested object.' The explicit New-Object approach recommended by Keith seems better!)

Tim Lovell-Smith
  • 15,310
  • 14
  • 76
  • 93
  • 8
    By strongly-typing the array as [byte[]] instead of untyped (which is actually [object[]]) you are removing all ambiguity when selecting the correct constructor. PowerShell will look for a constructor when performing a cast if there is no implicit or explicit cast available. – x0n Oct 13 '12 at 23:43
  • 1
    Same, explicitly adding types does nothing. Checking the expression containing the bytes, it already has type byte[], and not object[]. Using Keith Hills suggestion works fine. – Svend Sep 04 '17 at 11:46