Assuming you load the Newtonsoft.Json.dll
and BouncyCastle.Cryptography.dll
assemblies before invoking your script - e.g., with Add-Type -LiteralPath 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json\1.0.2.201\libs\Newtonsoft.Json.dll'
- you can define your class using PowerShell code, i.e. a PowerShell class
definition, as follows:
# Note: Assumes that Newtonsoft.Json.dll and BouncyCastle.Cryptography.dll
# were loaded *before* running this script.
class BigIntegerConverter : Newtonsoft.Json.JsonConverter {
[bool] CanConvert([Type] $objectType){
return $objectType -is [Org.BouncyCastle.Math.BigInteger]
}
[object] ReadJson([Newtonsoft.Json.JsonReader] $reader, [Type] $objectType, [object] $existingValue, [Newtonsoft.Json.JsonSerializer] $serializer) {
[bigint] $big = $reader.Value
return [Org.BouncyCastle.Math.BigInteger]::new($big.ToString())
}
WriteJson([Newtonsoft.Json.JsonWriter] $writer, [object] $value, [Newtonsoft.Json.JsonSerializer] $serializer) {
$writer.WriteRawValue($value.ToString())
}
}
The - unfortunate - requirement that any types referenced in a PowerShell class
have to have been loaded before the script at hand is parsed is discussed in this answer.
As for what you tried:
Mathias is correct in that you normally only need to make sure that the assemblies needed for compiling the C# code passed to Add-Type
be passed to -ReferencedAssemblies
.
For reasons unknown to me, with Newtonsoft.Json.dll
specifically, the code below additionally requires loading the Newtonsoft.Json.dll
assembly beforehand too.
- Note: The code below works in Windows PowerShell only - unlike the PowerShell
class
implementation above, which works in both editions.
- However, it can be made to work in PowerShell (Core) 7+, with extra effort:
Use the .NET Standard 2.0 implementation of NewtonSoft.Json.dll
(all implementations are part of the same Newtonsoft.Json
NuGet package)
- In the
-ReferencedAssemblies
argument:
- Add
netstandard
- Replace
System.Numerics
with System.Runtime.Numerics
- You then do not load
Newtonsoft.Json.dll
beforehand with Add-Type -LiteralPath
.
Alternatively, use the .NET (Core) implementation of the assembly:
- Follow the same steps as above, except for adding
netstandard
- Add
-IgnoreWarnings -WarningAction Ignore
to the Add-Type
call, to ignore and silence warnings regarding a version mismatch between PowerShell's .NET runtime version and the one targeted by Newtonsoft.Json.dll
If you accidentally use a .NET Framework implementation, you'll get errors about not finding core types such as Object
, presumably because they're looked for in .NET Framework assemblies.
$jsonAssembly = 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json\1.0.2.201\libs\Newtonsoft.Json.dll'
# Specify the path to BouncyCastle.Cryptography.dll here.
$bouncyCastleAssembly = 'C:\path\to\BouncyCastle.Cryptography.dll'
# !! Inexplicably, this is needed too, possibly also for BouncyCastle.Cryptography.dll
Add-Type -LiteralPath $jsonAssembly
Add-Type -ReferencedAssemblies $jsonAssembly, $bouncyCastleAssembly, System.Numerics -TypeDefinition @'
using System;
using System.Numerics;
using Newtonsoft.Json;
public class BigIntegerConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Org.BouncyCastle.Math.BigInteger));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
BigInteger big = (BigInteger)reader.Value;
return new Org.BouncyCastle.Math.BigInteger(big.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value.ToString());
}
'@
Also note:
The addition of using System;
to enable namespace-free references to class Type
The addition of System.Numerics
to -ReferencedAssemblies
as well as using System.Numerics;
to allow namespace-free references to BigInteger
Adding public
to the BigInterConverter
class definition to ensure that the resulting class is public.