Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
50def0b
updated Test-Json cmdlet to use JsonSchema.Net instead of NJsonSchema
gregsdennis Sep 3, 2022
3fd0a8a
change quoting of test-json tests
gregsdennis Sep 5, 2022
95241e8
adjust brace spacing to match examples in other commands
gregsdennis Sep 6, 2022
61f2dbd
remove space between closing curly brace and closing parenthesis
gregsdennis Sep 6, 2022
135f06a
configure for automatic downloads of external schemas
gregsdennis Sep 7, 2022
42592b5
use single quote strings when writing literal JSON values
gregsdennis Sep 7, 2022
ae5b85e
Update test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json…
iSazonov Sep 8, 2022
0fb4eb1
detect validation failures and report errors better
gregsdennis Sep 8, 2022
6e332eb
capture deserialization exception and record as failure to read ref'd…
gregsdennis Sep 9, 2022
ed4cdf0
remove component ids for pdb files from .wxs file
gregsdennis Sep 9, 2022
beb23b7
remove unused usings; add comment regarding json exception during val…
gregsdennis Sep 10, 2022
a571f08
add schema resolution exception; wrap fetch exceptions in new excepti…
gregsdennis Sep 11, 2022
115919e
use WriteError instead of throwing exception
gregsdennis Sep 11, 2022
42381a3
fix xml comments
gregsdennis Sep 11, 2022
0d1cca7
Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/Jso…
gregsdennis Sep 12, 2022
3e79360
Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tes…
gregsdennis Sep 12, 2022
8719102
use single-line method call; remove unused usings
gregsdennis Sep 12, 2022
ae3eb4d
enable nullable refs in JsonSchemaReferenceResolutionException.cs
gregsdennis Sep 17, 2022
cbc0d0b
move error string to resource file
gregsdennis Oct 5, 2022
ec7b35e
updated message construction to use resources for localization support
gregsdennis Feb 6, 2023
3b9bd80
Replace DllImport with LibraryImport in SMA 5 (#18580)
iSazonov Nov 22, 2022
9c43f51
updated Test-Json cmdlet to use JsonSchema.Net instead of NJsonSchema
gregsdennis Sep 3, 2022
b1f3d6a
adjust brace spacing to match examples in other commands
gregsdennis Sep 6, 2022
26faded
remove space between closing curly brace and closing parenthesis
gregsdennis Sep 6, 2022
097b11b
configure for automatic downloads of external schemas
gregsdennis Sep 7, 2022
8aaef47
use single quote strings when writing literal JSON values
gregsdennis Sep 7, 2022
e240b37
Update test/powershell/Modules/Microsoft.PowerShell.Utility/Test-Json…
iSazonov Sep 8, 2022
639ea31
detect validation failures and report errors better
gregsdennis Sep 8, 2022
6a385e1
capture deserialization exception and record as failure to read ref'd…
gregsdennis Sep 9, 2022
db20b2a
remove component ids for pdb files from .wxs file
gregsdennis Sep 9, 2022
467f049
remove unused usings; add comment regarding json exception during val…
gregsdennis Sep 10, 2022
51aea5a
add schema resolution exception; wrap fetch exceptions in new excepti…
gregsdennis Sep 11, 2022
843136b
use WriteError instead of throwing exception
gregsdennis Sep 11, 2022
edfc4b6
fix xml comments
gregsdennis Sep 11, 2022
df7cc4d
Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/Jso…
gregsdennis Sep 12, 2022
0cb49d0
Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/Tes…
gregsdennis Sep 12, 2022
31de5b6
use single-line method call; remove unused usings
gregsdennis Sep 12, 2022
6214b07
enable nullable refs in JsonSchemaReferenceResolutionException.cs
gregsdennis Sep 17, 2022
5005a3f
move error string to resource file
gregsdennis Oct 5, 2022
42f8b70
remove extra whitespace
SteveL-MSFT Feb 6, 2023
1ab6957
upated jsonschema.net package version
gregsdennis Feb 7, 2023
8380399
add error message without parameters; add comment for fetch method; d…
gregsdennis Feb 8, 2023
11380a1
remove whitespace
gregsdennis Feb 9, 2023
b8beee2
remove other extra whitespace; revert http to https
gregsdennis Feb 9, 2023
d847444
one last space
gregsdennis Feb 9, 2023
f17e245
update test-json tests for new message key
gregsdennis Feb 9, 2023
18ce041
fix typo on error message key
gregsdennis Feb 9, 2023
614e5cd
fix typo on error message key (actually, this time)
gregsdennis Feb 9, 2023
3e4594c
update package bom files
gregsdennis Mar 15, 2023
ecf5522
Update windows.json
TravisEz13 Mar 21, 2023
f6a1838
Merge branch 'master' into update-test-json-to-use-jsonschema.net
gregsdennis Apr 20, 2023
1fa1164
Remove an extra space in `TestJsonCmdletStrings.resx`
daxian-dbw May 1, 2023
6bb8baf
incorporate changes that allow better console output of errors
gregsdennis May 2, 2023
dc9200b
reintroduce changes from #19042 missed by faulty merge
gregsdennis May 2, 2023
4597c4d
Restore a newline to fix a CodeFactor issue
daxian-dbw May 2, 2023
a305b1c
Remove unused resource string
daxian-dbw May 2, 2023
7ba5026
move json parsing outside of try/catch so that it can throw its own e…
gregsdennis May 2, 2023
10182de
update tests to expect the correct error
gregsdennis May 2, 2023
654ae11
add missing variables to pester tests
gregsdennis May 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0-1.final" />
<PackageReference Include="System.Threading.AccessControl" Version="8.0.0-preview.3.23174.8" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0-preview.2.23128.3" />
<PackageReference Include="NJsonSchema" Version="10.8.0" />
<!-- NJsonSchema brings in an old version of CSharp
So, we are forcing a newer version.
-->
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="JsonSchema.Net" Version="3.3.2" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#nullable enable

using System;

namespace Microsoft.PowerShell.Commands;

/// <summary>
/// Thrown during evaluation of <see cref="TestJsonCommand"/> when an attempt
/// to resolve a <code>$ref</code> or <code>$dynamicRef</code> fails.
/// </summary>
internal class JsonSchemaReferenceResolutionException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="JsonSchemaReferenceResolutionException"/> class.
/// </summary>
/// <param name="innerException">
/// The exception that is the cause of the current exception, or a null reference
/// (<code>Nothing</code> in Visual Basic) if no inner exception is specified.
/// </param>
public JsonSchemaReferenceResolutionException(Exception innerException)
: base(message: null, innerException)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
using System.Globalization;
using System.IO;
using System.Management.Automation;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Net.Http;
using System.Security;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using System.Text.Json;
using System.Text.Json.Nodes;
using Json.Schema;

namespace Microsoft.PowerShell.Commands
{
Expand Down Expand Up @@ -104,36 +104,50 @@ public string LiteralPath
private bool _isLiteralPath = false;
private JsonSchema _jschema;

/// <summary>
/// Process all exceptions in the AggregateException.
/// Unwrap TargetInvocationException if any and
/// rethrow inner exception without losing the stack trace.
/// </summary>
/// <param name="e">AggregateException to be unwrapped.</param>
/// <returns>Return value is unreachable since we always rethrow.</returns>
private static bool UnwrapException(Exception e)
{
if (e.InnerException != null && e is TargetInvocationException)
{
ExceptionDispatchInfo.Capture(e.InnerException).Throw();
}
else
{
ExceptionDispatchInfo.Capture(e).Throw();
}

return true;
}

#endregion

#region Protected Members

/// <summary>
/// Prepare a JSON schema.
/// </summary>
protected override void BeginProcessing()
{
// By default, a JSON Schema implementation isn't supposed to automatically fetch content.
// Instead JsonSchema.Net has been set up with a registry so that users can pre-register
// any schemas they may need to resolve.
// However, pre-registering schemas doesn't make sense in the context of a Powershell command,
// and automatically fetching referenced URIs is likely the preferred behavior. To do that,
// this property must be set with a method to retrieve and deserialize the content.
// For more information, see https://json-everything.net/json-schema#automatic-resolution
SchemaRegistry.Global.Fetch = static uri =>
{
try
{
string text;
switch (uri.Scheme)
{
case "http":
case "https":
{
using var client = new HttpClient();
text = client.GetStringAsync(uri).Result;
break;
}
case "file":
var filename = Uri.UnescapeDataString(uri.AbsolutePath);
text = File.ReadAllText(filename);
break;
default:
throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme));
}

return JsonSerializer.Deserialize<JsonSchema>(text);
}
catch (Exception e)
{
throw new JsonSchemaReferenceResolutionException(e);
}
};

string resolvedpath = string.Empty;

try
Expand All @@ -142,25 +156,25 @@ protected override void BeginProcessing()
{
try
{
_jschema = JsonSchema.FromJsonAsync(Schema).Result;
_jschema = JsonSchema.FromText(Schema);
}
catch (AggregateException ae)
catch (JsonException e)
{
// Even if only one exception is thrown, it is still wrapped in an AggregateException exception
// https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
ae.Handle(UnwrapException);
Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e);
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Schema));
}
}
else if (SchemaFile != null)
{
try
{
resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile);
_jschema = JsonSchema.FromFileAsync(resolvedpath).Result;
_jschema = JsonSchema.FromFile(resolvedpath);
}
catch (AggregateException ae)
catch (JsonException e)
{
ae.Handle(UnwrapException);
Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e);
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile));
}
}
}
Expand Down Expand Up @@ -194,6 +208,7 @@ e is SecurityException
protected override void ProcessRecord()
{
bool result = true;

string jsonToParse = string.Empty;

if (Json != null)
Expand All @@ -217,45 +232,57 @@ protected override void ProcessRecord()
jsonToParse = File.ReadAllText(resolvedPath);
}

if (string.IsNullOrWhiteSpace(jsonToParse))
{
WriteObject(false);
return;
}

try
{
var parsedJson = JToken.Parse(jsonToParse);

var parsedJson = JsonNode.Parse(jsonToParse);

if (_jschema != null)
{
var errorMessages = _jschema.Validate(parsedJson);
if (errorMessages != null && errorMessages.Count != 0)
{
result = false;

Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema);

foreach (var message in errorMessages)
var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic });
result = validationResults.IsValid;
if (!result)
{
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null);
errorRecord.ErrorDetails = new ErrorDetails(message.ToString());
WriteError(errorRecord);
if (validationResults.Message != null)
{
Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, validationResults.Message, validationResults.InstanceLocation));
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null);
WriteError(errorRecord);
}

if (validationResults.HasNestedResults)
{
foreach (var nestedResult in validationResults.NestedResults)
{
if (nestedResult.Message == null)
{
continue;
}

Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, nestedResult.Message, nestedResult.InstanceLocation));
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null);
WriteError(errorRecord);
}
}
}
}
}
}
catch (JsonSchemaReferenceResolutionException jsonExc)
{
result = false;

Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc);
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema));
}
catch (Exception exc)
{
result = false;

Exception exception = new(TestJsonCmdletStrings.InvalidJson, exc);
WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, jsonToParse));
WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, Json));
}

WriteObject(result);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,13 @@
<data name="InvalidJson" xml:space="preserve">
<value>Cannot parse the JSON.</value>
</data>
<data name="InvalidJsonAgainstSchema" xml:space="preserve">
<value>The JSON is not valid with the schema.</value>
<data name="InvalidJsonAgainstSchemaDetailed" xml:space="preserve">
<value>The JSON is not valid with the schema: {0} at {1}</value>
</data>
<data name="JsonSchemaFileOpenFailure" xml:space="preserve">
<value>Can not open JSON schema file: {0}</value>
</data>
<data name="InvalidUriScheme" xml:space="preserve">
<value>URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed.</value>
</data>
</root>
Loading