Escaping Quotes and Backslashes in JSON

This blog discusses escaping quotes and backslashes in JSON.

I was doing a deep(er) dive into Microsoft’s Package Support Framework for MSIX recently, and wanted to have a play around with some of the “fixups” provided.

Whilst I was fiddling around trying to make things work (due to Microsoft’s inaccurate and/or poorly documented examples!), I stumbled upon shortcut arguments inside a config.json file and thought I’d write a short blog post to highlight escaping quotes and backslashes in JSON.

Escaping Quotes and Backslashes in JSON

When we escape a character in JSON, we essentially prefix the character with a backslash (\).  So a " would become \" and a \ would become \\.

The example we will use is to JSON encode the following string argument:

-logfile "%TEMP%\Alkane Path\alkane.log"

We notice that the log file path contains a space, so we need to surround the path in quotes.

Escaping Backslashes in JSON

The first step is to escape the backslashes by prefixing them with another backslash like so:

-logfile "%TEMP%\\Alkane Path\\alkane.log"

Escaping Quotes in JSON

The second step is to escape the quotes with a backslash like so:

-logfile \"%TEMP%\\Alkane Path\\alkane.log\"

JSON Encoded String

We then paste this value into our config.json file (excerpt):

{
    "arguments": ""
}

Which results in a valid JSON file like so:

{
    "arguments": "-logfile \"%TEMP%\\Alkane Path\\alkane.log\""
}

Most people probably won’t want (or need) to understand this level of detail since they’ll use the GUI of the MSIX Packaging Tool to apply fixups.  But it’s useful to understand JSON for a plethora of other RESTful APIs, as well as our own free MSIX packaging tool.

Using PowerShell to Read and Write JSON (Updated)

This blog provides a simple example of using PowerShell to read and write JSON.

PowerShell and JSON – Objects, Arrays, Hashtables and Ordering

For the context of this post, think of an example JSON object being a “school”, a JSON property name being the school’s name, and an array being a list of classes in that school.  We can write it like so:

$school=@{
    name="Alkane High School"
    class=@{        
        name="1AB"
        teacher="Joe Bloggs"
    }
}
$school | convertto-json

and this will output

{
    "class":  {
                  "teacher":  "Joe Bloggs",
                  "name":  "1AB"
              },
    "name":  "Alkane High School"
}

Notice how the school name appears last, when we declared it first in our JSON object?  We can correct that by specifying [ordered] in front of the school hashtable like so:

$school=[ordered]@{
    name="Alkane High School"
    class=@{        
        name="1AB"
        teacher="Joe Bloggs"
    }
}

Giving us this output:

{
    "name":  "Alkane High School",
    "class":  {
                  "teacher":  "Joe Bloggs",
                  "name":  "1AB"
              }
}

Do you also notice that the output for the class is not an array with square brackets, which implies there cannot be multiple classes in a school?  We can fix this by either adding another class like so:

$school=[ordered]@{
    name="Alkane High School"
    class=@{        
        name="1AB"
        teacher="Joe Bloggs"
    },@{        
        name="2AB"
        teacher="Peter Pan"
    }
}
$school | convertto-json

Which now automatically creates the array [] since there is more than one class:

{
    "name":  "Alkane High School",
    "class":  [
                  {
                      "teacher":  "Joe Bloggs",
                      "name":  "1AB"
                  },
                  {
                      "teacher":  "Peter Pan",
                      "name":  "2AB"
                  }
              ]
}

Or, we can simply force PowerShell to use an array by prefixing the @ with a comma like so:

$school=[ordered]@{
    name="Alkane High School"
    class=,@{        
        name="1AB"
        teacher="Joe Bloggs"
    }
}
$school | convertto-json

Producing the following output:

{
    "name":  "Alkane High School",
    "class":  [
                  {
                      "teacher":  "Joe Bloggs",
                      "name":  "1AB"
                  }
              ]
}

Remember that we create JSON objects (the school) by using the syntax for a hashtable, which is simply: @{

When we want to create a JSON array [], we can prefix the @ with a comma ,@{ to force a JSON array.

Annoying Gotcha When Testing PowerShell with JSON

When our object becomes more complex with nested entries, we usually want to test the output using the convertto-json cmdlet.  Consider this nested example:

$school=[ordered]@{
    name="Alkane High School"
    class=,@{        
        name="1AB"
        teacher="Joe Bloggs"
        student=@{
            "Name"="Peter"
        },
        @{
            "Name"="Rachel"
        }
    }
}
$school | convertto-json

where the output is:

{
    "name":  "Alkane High School",
    "class":  [
                  {
                      "name":  "1AB",
                      "teacher":  "Joe Bloggs",
                      "student":  "System.Collections.Hashtable System.Collections.Hashtable"
                  }
              ]
}

When i first saw this, I thought seeing System.Collections.Hashtable was some kind of error when creating JSON objects using PowerShell!  But it wasn’t!  We merely needed to increase the default depth when converting our JSON object like so!

$school | convertto-json -Depth 4

Using PowerShell to Write JSON

In this example, we first create a PowerShell object with some sample properties and nested objects. We then use the ConvertTo-Json cmdlet to convert the PowerShell object to a JSON string. Finally, we use the Set-Content cmdlet to save the JSON string to a file.

This example shows how to read and write JSON using PowerShell, and can be customized to fit the specific needs of your JSON data.

$obj = @{
    "PropertyName" = "PropertyValue"
    "ObjectName" = @{
        "ObjectPropertyName" = "ObjectPropertyValue"
    }
}

# Convert object to JSON
$json = $obj | ConvertTo-Json

# Save JSON to file
$json | Set-Content -Path C:\alkane\example.json

Using PowerShell to Read JSON

In this example, we first load a JSON file using the Get-Content cmdlet and pass the -Raw parameter to read the entire file as a single string. We then use the ConvertFrom-Json cmdlet to convert the JSON string to a PowerShell object. We can then access specific properties within the JSON object using dot notation.

# Load JSON file
$json = Get-Content -Path C:\alkane\example.json -Raw | ConvertFrom-Json

# Access JSON properties
$json.PropertyName
$json.ObjectName.PropertyName

Using PowerShell to Iterate Through JSON

Let’s suppose our JSON file has more than one object with multiple properties (key/value pairs) like so:

$obj = @{
    "ObjectName1" = @{
        "Object1PropertyName1" = "Object1PropertyValue1"
        "Object1PropertyName2" = "Object1PropertyValue2"
    }
    "ObjectName2" = @{
        "Object2PropertyName1" = "Object2PropertyValue1"
        "Object2PropertyName2" = "Object2PropertyValue2"
    }
}

# Convert object to JSON
$json = $obj | ConvertTo-Json

# Save JSON to file
$json | Set-Content -Path C:\alkane\example.json

We might then want to loop through these objects and properties to read each value.  We can do this like so:

# Load JSON file
$json = Get-Content -Path C:\alkane\example.json -Raw | ConvertFrom-Json

# Loop through the objects in the JSON data
foreach ($object in $json.PSObject.Properties) {

    Write-Host "Object name: $($object.Name)"
  
    $objectproperties = Get-Member -InputObject $object.Value -MemberType NoteProperty
  
    foreach($property in $objectproperties) {
        Write-Host "Property name: $($property.Name)"
        Write-Host "Property value: $($object.Value.($property.Name))"
    }

}

It’s also worth familiarising yourself with escaping quotes and backslashes in JSON.