diff --git a/.azure-pipelines/generation-templates/authentication-module.yml b/.azure-pipelines/generation-templates/authentication-module.yml
index 86b7171a52..4dc2d7148d 100644
--- a/.azure-pipelines/generation-templates/authentication-module.yml
+++ b/.azure-pipelines/generation-templates/authentication-module.yml
@@ -30,6 +30,15 @@ steps:
script: |
. $(System.DefaultWorkingDirectory)/tools/GenerateAuthenticationModule.ps1 -Test
+ - ${{ if eq(parameters.Test, true) }}:
+ - task: PowerShell@2
+ displayName: Test Json Utilities
+ inputs:
+ pwsh: true
+ targetType: inline
+ script: dotnet test
+ workingDirectory: "$(System.DefaultWorkingDirectory)/tools/Tests/JsonUtilitiesTest"
+
- ${{ if eq(parameters.Sign, true) }}:
- template: ../common-templates/esrp/strongname.yml
parameters:
diff --git a/autorest.powershell b/autorest.powershell
index 1865c6e579..e2dd039108 160000
--- a/autorest.powershell
+++ b/autorest.powershell
@@ -1 +1 @@
-Subproject commit 1865c6e579269c45a45ad1c6cf6d856b6d27643f
+Subproject commit e2dd0391085d76318d6f19001dce7938eb8281e1
diff --git a/src/readme.graph.md b/src/readme.graph.md
index 3d0df15c85..3e7b0ef49b 100644
--- a/src/readme.graph.md
+++ b/src/readme.graph.md
@@ -335,6 +335,11 @@ directive:
let dateTimeToJsonRegex = /(\.Json\.JsonString\()(.*)\?(\.ToString\(@"yyyy'-'MM'-'dd'T'HH':'mm':'ss\.fffffffK")/gm
$ = $.replace(dateTimeToJsonRegex, '$1System.DateTime.SpecifyKind($2.Value.ToUniversalTime(), System.DateTimeKind.Utc)$3');
+ // Enables null valued properties
+ $ = $.replace(/AddIf\(\s*null\s*!=\s*(this\._\w+)\s*\?\s*\(\s*Microsoft\.Graph\.PowerShell\.Runtime\.Json\.JsonNode\)\s*(.*)\s*:\s*null\s*,\s*"(.*?)"\s*,\s*container\.Add\s*\)/gm, 'container.Add("$3", $1 != null ? (Microsoft.Graph.PowerShell.Runtime.Json.JsonNode) $2 :"defaultnull")')
+
+ $ = $.replace(/AddIf\(\s*null\s*!=\s*\(\(\(\(object\)\s*(this\._\w+)\)\)?.ToString\(\)\)\s*\?\s*\(\s*Microsoft\.Graph\.PowerShell\.Runtime\.Json\.JsonNode\)\s*new\s*Microsoft\.Graph\.PowerShell\.Runtime\.Json\.JsonString\((this\._\w+).ToString\(\)\)\s*:\s*null\s*,\s*"(.*?)"\s*,\s*container\.Add\s*\)/gm, 'container.Add("$3", $1 != null ? (Microsoft.Graph.PowerShell.Runtime.Json.JsonNode) new Microsoft.Graph.PowerShell.Runtime.Json.JsonString($2.ToString()) :"defaultnull")');
+
return $;
}
# Modify generated .dictionary.cs model classes.
diff --git a/tools/Custom/JsonExtensions.cs b/tools/Custom/JsonExtensions.cs
new file mode 100644
index 0000000000..0c0a69d888
--- /dev/null
+++ b/tools/Custom/JsonExtensions.cs
@@ -0,0 +1,62 @@
+namespace Microsoft.Graph.PowerShell.JsonUtilities
+{
+ using Newtonsoft.Json.Linq;
+ using System.Linq;
+
+ public static class JsonExtensions
+ {
+ ///
+ /// Removes JSON properties that have a value of "defaultnull" and converts properties with values of "null" to actual JSON null values.
+ ///
+ /// The JObject to process and clean.
+ ///
+ /// A JSON string representation of the cleaned JObject with "defaultnull" properties removed and "null" values converted to JSON null.
+ ///
+ ///
+ /// JObject json = JObject.Parse(@"{""name"": ""John"", ""email"": ""defaultnull"", ""address"": ""null""}");
+ /// string cleanedJson = json.RemoveDefaultNullProperties();
+ /// Console.WriteLine(cleanedJson);
+ /// // Output: { "name": "John", "address": null }
+ ///
+ public static string RemoveDefaultNullProperties(this JObject jsonObject)
+ {
+ try
+ {
+ foreach (var property in jsonObject.Properties().ToList())
+ {
+ if (property.Value.Type == JTokenType.Object)
+ {
+ RemoveDefaultNullProperties((JObject)property.Value);
+ }
+ else if (property.Value.Type == JTokenType.Array)
+ {
+ foreach (var item in property.Value)
+ {
+ if (item.Type == JTokenType.Object)
+ {
+ RemoveDefaultNullProperties((JObject)item);
+ }
+ }
+ }
+ else if (property.Value.Type == JTokenType.String && property.Value.ToString() == "defaultnull")
+ {
+ property.Remove();
+ }
+ else if (property.Value.Type == JTokenType.String && (property.Value.ToString() == "null"))
+ {
+ property.Value = JValue.CreateNull();
+ }
+ }
+ }
+ catch (System.Exception)
+ {
+ return jsonObject.ToString(); // Return the original string if parsing fails
+ }
+ return jsonObject.ToString();
+ }
+ public static string ReplaceAndRemoveSlashes(this string body)
+ {
+ return body.Replace("/", "").Replace("\\", "").Replace("rn", "").Replace("\"{", "{").Replace("}\"", "}");
+ }
+ }
+}
diff --git a/tools/Tests/JsonUtilitiesTest/JsonExtensionsTests.cs b/tools/Tests/JsonUtilitiesTest/JsonExtensionsTests.cs
new file mode 100644
index 0000000000..ed45257e94
--- /dev/null
+++ b/tools/Tests/JsonUtilitiesTest/JsonExtensionsTests.cs
@@ -0,0 +1,128 @@
+namespace JsonUtilitiesTest;
+using System;
+using Newtonsoft.Json.Linq;
+using Xunit;
+using Microsoft.Graph.PowerShell.JsonUtilities;
+
+public class JsonExtensionsTests
+{
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldRemoveDefaultNullValues()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{
+ ""displayname"": ""Tim"",
+ ""position"": ""defaultnull"",
+ ""salary"": 2000000,
+ ""team"": ""defaultnull""
+ }");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.False(result.ContainsKey("position"));
+ Assert.False(result.ContainsKey("team"));
+ Assert.Equal("Tim", result["displayname"]?.ToString());
+ Assert.Equal(2000000, result["salary"]?.ToObject());
+ }
+
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldConvertStringNullToJsonNull()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{
+ ""displayname"": ""Tim"",
+ ""position"": ""null"",
+ ""salary"": 2000000,
+ ""team"": """"
+ }");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.Null(result["position"]?.Value());
+ Assert.Equal("",result["team"]?.ToString());
+ Assert.Equal("Tim", result["displayname"]?.ToString());
+ Assert.Equal(2000000, result["salary"]?.ToObject());
+ }
+
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldHandleNestedObjects()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{
+ ""displayname"": ""Tim"",
+ ""metadata"": {
+ ""phone"": ""defaultnull"",
+ ""location"": ""Nairobi""
+ }
+ }");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.False(result["metadata"]?.ToObject()?.ContainsKey("phone"));
+ Assert.Equal("Nairobi", result["metadata"]?["location"]?.ToString());
+ }
+
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldHandleEmptyJsonObject()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{}");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.Empty(result);
+ }
+
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldHandleJsonArrays()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{
+ ""users"": [
+ { ""displayname"": ""Tim"", ""email"": ""defaultnull"" },
+ { ""displayname"": ""Mayabi"", ""email"": ""mayabi@example.com"" }
+ ]
+ }");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.Equal("Tim", result["users"]?[0]?["displayname"]?.ToString());
+ Assert.Equal("mayabi@example.com", result["users"]?[1]?["email"]?.ToString());
+ }
+
+ [Fact]
+ public void RemoveDefaultNullProperties_ShouldNotAlterValidData()
+ {
+ // Arrange
+ JObject json = JObject.Parse(@"{
+ ""displayname"": ""Tim"",
+ ""email"": ""mayabi@example.com"",
+ ""salary"": 2000000
+ }");
+
+ // Act
+ string cleanedJson = json.RemoveDefaultNullProperties();
+ JObject result = JObject.Parse(cleanedJson);
+
+ // Assert
+ Assert.Equal("Tim", result["displayname"]?.ToString());
+ Assert.Equal("mayabi@example.com", result["email"]?.ToString());
+ Assert.Equal(2000000, result["salary"]?.ToObject());
+ }
+}
+
diff --git a/tools/Tests/JsonUtilitiesTest/JsonUtilitiesTest.csproj b/tools/Tests/JsonUtilitiesTest/JsonUtilitiesTest.csproj
new file mode 100644
index 0000000000..2db61912cf
--- /dev/null
+++ b/tools/Tests/JsonUtilitiesTest/JsonUtilitiesTest.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../../Custom/JsonExtensions.cs
+
+
+
+