ConvertFrom-JsonFast.psm1
Add-Type -TypeDefinition @"
using System; using System.IO; using System.Linq; using System.Collections; using System.Text.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; public static class JsonHelper { public static object Deserialize(string json, Int32 depth) { JsonDocumentOptions options = new JsonDocumentOptions(); options.MaxDepth = depth; JsonDocument thisDocument = JsonDocument.Parse(json, options); return ToObject(thisDocument.RootElement); } public static object ToObject(JsonElement element) { JsonValueKind thisKind = element.ValueKind; switch (element.ValueKind) { case JsonValueKind.Object: var Properties = element.EnumerateObject(); return new Hashtable(Properties.ToDictionary(prop => prop.Name, prop => ToObject(prop.Value) )); case JsonValueKind.Array: var Entries = element.EnumerateArray(); return Entries.Select(ToObject).ToArray(); case JsonValueKind.True: return true; case JsonValueKind.False: return false; case JsonValueKind.String: return element.GetString(); case JsonValueKind.Number: if (element.TryGetInt32(out _)) { return element.GetInt32(); } if (element.TryGetInt64(out _)) { return element.GetInt64(); } return element.GetDouble(); default: return null; } } } "@ -ReferencedAssemblies netstandard,System.Collections,System.Linq,System,System.IO,System.Text.Json,Newtonsoft.Json,System.Memory Function ConvertFrom-JsonFast { <# .SYNOPSIS Converts a json string to a real object .DESCRIPTION Converts a json string to a real object .PARAMETER InputObject The string of json to convert .EXAMPLE ConvertFrom-JsonFast -InputObject "{""Tom"": 5}" .NOTES Objects will be returned as Hashtables and not as pscustomobjects #> param ( [Parameter(ValuefromPipeline=$True)] $InputObject, [int] $Depth = 1024, [switch] $AsHashtable, [switch] $NoEnumerate ) begin { $ObjectBuffer = [System.Collections.ArrayList]::new() } process { [void] $ObjectBuffer.Add($InputObject) } end { # If our buffer only has one element in it we use this fast path. Otherwise the try{} catch{} block later will cause us to deserialize the object twice. if ($ObjectBuffer.count -eq 1) { $result = [JsonHelper]::Deserialize($ObjectBuffer[0], $depth) } # We want to support a user passing us two discrete json objects via the pipeline where we deserialize both. So we attempt to # deserialize the first object and if it works we then deserialize each object as if it is its own json object. else { try { [void] ([JsonHelper]::Deserialize($ObjectBuffer[0], $depth)) $Result = @(foreach ($item in $ObjectBuffer) { [JsonHelper]::Deserialize($item, $depth) }) } catch { # If that fails we just take the whole input, concatenate it, and pass it to the parser. $Result = [JsonHelper]::Deserialize([string]::join("`n",$ObjectBuffer.ToArray()), $depth) } } # The noenumerate flag allows the returning of an array without unpacking it. if ($NoEnumerate) { # We have to force return an array otherwise powershell will collapse a one element array if ($Result -is [array]) { return @(,$result) } } return $result } } Function Invoke-RestMethodFast { <# .SYNOPSIS Connects to a remote host and returns the content of the body casted to objects .DESCRIPTION Connects to a remote host and returns the content of the body casted to objects .EXAMPLE Invoke-RestMethodfast -Uri https://jsonplaceholder.typicode.com/todos/1 .NOTES Supports any additional parameters that invoke-webrequest supports. Will only work with JSON, does not work with XML #> # Proxy all of the parameters to invoke-webrequest so that this can be a drop-in for invoke-restmethod $params = $MyInvocation.UnboundArguments $result = Invoke-WebRequest @params ConvertFrom-JsonFast -InputObject $Result } Set-Alias -Name Invoke-FastRestMethod -Value Invoke-RestMethodFast Set-Alias -Name ConvertFrom-FastJson -Value ConvertFrom-JsonFast |