163 lines
6.1 KiB
PowerShell
163 lines
6.1 KiB
PowerShell
|
function Write-OrderedJsonByArray {
|
||
|
<#
|
||
|
.SYNOPSIS
|
||
|
Given a PSCustomObject, write it as pretty indented json WITH ORDERING for consistency
|
||
|
|
||
|
.PARAMETER JsonObject
|
||
|
An object that should be written as json. Should be a PSCustomObject or Hashtable
|
||
|
|
||
|
.PARAMETER NoKeyReorder
|
||
|
[switch] Should avoid reordering keys
|
||
|
|
||
|
.PARAMETER Path
|
||
|
A filesystem path
|
||
|
#>
|
||
|
[CmdletBinding()]
|
||
|
[OutputType([string])]
|
||
|
param (
|
||
|
# Setting to mandatory false because it can be null and that's ok, we just return null
|
||
|
[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
|
||
|
$JsonObject,
|
||
|
[switch]$NoKeyReorder,
|
||
|
[Parameter(Mandatory = $false)]
|
||
|
$Path
|
||
|
)
|
||
|
|
||
|
#region innerFunctions
|
||
|
$script:fullText = @()
|
||
|
$quoteString = '"'
|
||
|
$commaString = ","
|
||
|
$OrderedKeys = !$NoKeyReorder
|
||
|
$primitiveMatch = 'byte|short|int32|long|sbyte|ushort|uint32|ulong|float|double|decimal|boolean'
|
||
|
|
||
|
function Get-JsonStringLeadsByDepth {
|
||
|
param (
|
||
|
$Depth = 0
|
||
|
)
|
||
|
|
||
|
$spacesString = [string]::new(" ", ($Depth + 1) * 2)
|
||
|
$shortSpacesString = ""
|
||
|
if ($Depth -gt 0) {
|
||
|
$shortSpacesString = [string]::new(" ", $Depth * 2)
|
||
|
}
|
||
|
|
||
|
return ($spacesString, $shortSpacesString)
|
||
|
}
|
||
|
|
||
|
function Build-JsonArrayNameValuePair {
|
||
|
param (
|
||
|
$JsonName,
|
||
|
$JsonValue,
|
||
|
$Depth = 0
|
||
|
)
|
||
|
|
||
|
$spacesString, $shortSpacesString = (Get-JsonStringLeadsByDepth -Depth $Depth)
|
||
|
|
||
|
if ($OrderedKeys) {
|
||
|
$JsonValue = $JsonValue | Sort-Object -Property Name,Key,Id
|
||
|
}
|
||
|
|
||
|
$header = ""
|
||
|
if (![string]::IsNullOrWhiteSpace($JsonName)) {
|
||
|
$header = "$quoteString$JsonName$quoteString : "
|
||
|
}
|
||
|
$header = "$shortSpacesString$header["
|
||
|
$script:fullText += $header
|
||
|
|
||
|
foreach ($iter in $JsonValue) {
|
||
|
if ($iter.GetType().Name -match $primitiveMatch) {
|
||
|
# Write it without quotes
|
||
|
$script:fullText += "$spacesString$iter$commaString"
|
||
|
} elseif ($iter -is [string]) {
|
||
|
# Write it with quotes
|
||
|
$script:fullText += "$spacesString$quoteString$iter$quoteString$commaString"
|
||
|
} else {
|
||
|
# Must be a complex object, but without a name, so write the value
|
||
|
Build-JsonObject -JsonName $null -JsonValue $iter -Depth ($Depth + 1)
|
||
|
}
|
||
|
}
|
||
|
$script:fullText += "$shortSpacesString]$commaString"
|
||
|
}
|
||
|
|
||
|
function Build-JsonObject {
|
||
|
param (
|
||
|
$JsonName,
|
||
|
$JsonValue,
|
||
|
$Depth = 0
|
||
|
)
|
||
|
|
||
|
$spacesString, $shortSpacesString = (Get-JsonStringLeadsByDepth -Depth $Depth)
|
||
|
|
||
|
$header = ""
|
||
|
if (![string]::IsNullOrWhiteSpace($JsonName)) {
|
||
|
$header = "$quoteString$JsonName$quoteString : "
|
||
|
}
|
||
|
$header = "$shortSpacesString$header{"
|
||
|
$script:fullText += $header
|
||
|
|
||
|
if (!(Test-IsCollectionNullOrEmpty $JsonValue.PSObject.Properties.Where({$_.MemberType -eq 'NoteProperty'}))) {
|
||
|
$JsonValue = $JsonValue.PSObject.Properties.Where({$_.MemberType -eq 'NoteProperty'})
|
||
|
}
|
||
|
if ($OrderedKeys) {
|
||
|
$JsonValue = $JsonValue | Sort-Object -Property Name, Key, Id
|
||
|
}
|
||
|
$keys = $JsonValue.Keys
|
||
|
if (Test-IsCollectionNullOrEmpty $keys) {
|
||
|
$keys = $JsonValue.Name
|
||
|
}
|
||
|
foreach ($key in $keys) {
|
||
|
$iter = $JsonValue[$key]
|
||
|
if ($null -eq $iter) {
|
||
|
$posit = $JsonValue.Where({$_.Name -eq $key})
|
||
|
if ($null -ne $posit) {
|
||
|
$iter = $posit.Value
|
||
|
}
|
||
|
}
|
||
|
if ($null -eq $iter) {
|
||
|
$script:fullText += "$spacesString$quoteString$key$quoteString : null$commaString"
|
||
|
} else {
|
||
|
if ($iter -ceq "False") { $iter = $false }
|
||
|
if ($iter -ceq "True") { $iter = $true }
|
||
|
if ($iter.GetType().Name -match $primitiveMatch) {
|
||
|
$script:fullText += "$spacesString$quoteString$key$quoteString : $($iter.ToString().ToLower())$commaString"
|
||
|
} elseif ($iter -is [string]) {
|
||
|
$script:fullText += "$spacesString$quoteString$key$quoteString : $quoteString$iter$quoteString$commaString"
|
||
|
} elseif ($iter.GetType().IsArray) {
|
||
|
# values are an array, so let's write the array values
|
||
|
Build-JsonArrayNameValuePair -JsonName $key -JsonValue $iter -Depth ($Depth + 1)
|
||
|
} else {
|
||
|
# It was not an array, or a primitive, so it must be _another_ object?
|
||
|
Build-JsonObject -JsonName $key -JsonValue $iter -Depth ($Depth + 1)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$script:fullText += "$shortSpacesString}$commaString"
|
||
|
}
|
||
|
#endregion innerFunctions
|
||
|
|
||
|
if ($JsonObject -is [string]) {
|
||
|
return $JsonObject
|
||
|
} elseif ($JsonObject -is [bool]) {
|
||
|
return $JsonObject.ToString()
|
||
|
} elseif ($JsonObject.GetType().Name -match $primitiveMatch) {
|
||
|
return $JsonObject.ToString()
|
||
|
} elseif ($JsonObject.GetType().IsArray) {
|
||
|
(Build-JsonArrayNameValuePair -JsonName $null -JsonValue $JsonObject -Depth 0)
|
||
|
} else {
|
||
|
(Build-JsonObject -JsonName $null -JsonValue $JsonObject -Depth 0)
|
||
|
}
|
||
|
|
||
|
# postprocess to convert this string: ",(\r?\n?\s*?[\]\}])" to this string "$1" (mind the escaping tho)
|
||
|
# That string says "any comma followed by any newline character(s) and any number of spaces, followed by a closing brace (indicating the end of an array or object) should remove the comma but retain the rest of the string"
|
||
|
# This removes trailing commas in arrays and object notations
|
||
|
$regex = New-Object System.Text.RegularExpressions.Regex(",(\r?\n?\s*?[\]\}])")
|
||
|
$builtString = [string]::Join([System.Environment]::NewLine,$script:fullText)
|
||
|
$builtString = $regex.Replace($builtString, "`$1")
|
||
|
$builtString = $builtString.TrimEnd().TrimEnd(",")
|
||
|
|
||
|
if ([string]::IsNullOrWhiteSpace($Path)) {
|
||
|
return $builtString
|
||
|
} else {
|
||
|
Set-Content -Path $Path -Value $builtString -Force | Out-Null
|
||
|
}
|
||
|
}
|