# JSON: ConvertFrom-Json and ConvertTo-Json

JSON is the text format most apps keep their settings in and most websites send their data in, and PowerShell reads it into an object with ConvertFrom-Json, lets you change a value with a dot and an equals sign, and writes it back with ConvertTo-Json, whose -Depth says how many levels of boxes inside boxes it keeps.

Journeyman · PowerShell · Operating System · Updated November 10, 2026

## After this lesson you can

- Read a JSON settings file into an object with Get-Content -Raw and ConvertFrom-Json, and reach values inside it with dots
- Change a setting and save the file again with ConvertTo-Json -Depth and Set-Content, after making a backup copy

## Key takeaways

- JSON writes data as labels and values: `{ }` holds an object's labels and values, and `[ ]` holds a list.
- `Get-Content booking-settings.json -Raw | ConvertFrom-Json` reads the whole file into an object, and dots reach inside it: `$settings.rentalPrices.eBike`.
- Copy the file first, change a value with `=`, then save it with `ConvertTo-Json -Depth 5 | Set-Content`.
- `ConvertTo-Json` goes only two levels deep unless `-Depth` says more, and writes anything deeper as text such as `@{weekdays=…}`.

The bike shop's booking website reads its rental prices and opening hours from a settings file, `booking-settings.json`. From next week, e-bikes cost $28 an hour instead of $25, and the person who set up the site is away. You could open the file in Notepad and change the number, and many people do. But one missing comma or quote in a file like this, and the app won't start. Lots of programs keep their settings this way: VS Code, Windows Terminal, a game's options, a website's setup, and most web APIs send their answers in the same format. PowerShell reads the file into an object, changes one value, and writes the file back in the right shape every time. A web developer changing a site's setup and an IT tech changing one setting on fifty computers both work this way.

## Labels and values: what JSON looks like

Copy these lines into PowerShell to make the settings file. Running them again is safe, and puts the file back the way it started.

```powershell
New-Item -ItemType Directory -Force -Path "$HOME\terminal-practice\bike-shop" | Out-Null
Set-Content -Path "$HOME\terminal-practice\bike-shop\booking-settings.json" -Value '{', '  "shopName": "Maple Street Bikes",', '  "sendReminders": true,', '  "rentalPrices": {', '    "cityBike": 12,', '    "eBike": 25,', '    "kidsBike": 8', '  },', '  "stores": [', '    {', '      "name": "Downtown",', '      "phone": "555-0142",', '      "hours": { "weekdays": "9:00-18:00", "saturday": "10:00-16:00" }', '    },', '    {', '      "name": "Riverside",', '      "phone": "555-0178",', '      "hours": { "weekdays": "10:00-18:00", "saturday": "10:00-17:00" }', '    }', '  ]', '}'
```

They print nothing when they work. Read the file:

```powershell
Set-Location "$HOME\terminal-practice\bike-shop"
Get-Content booking-settings.json
```

```text
{
  "shopName": "Maple Street Bikes",
  "sendReminders": true,
  "rentalPrices": {
    "cityBike": 12,
    "eBike": 25,
    "kidsBike": 8
  },
  "stores": [
    {
      "name": "Downtown",
      "phone": "555-0142",
      "hours": { "weekdays": "9:00-18:00", "saturday": "10:00-16:00" }
    },
    {
      "name": "Riverside",
      "phone": "555-0178",
      "hours": { "weekdays": "10:00-18:00", "saturday": "10:00-17:00" }
    }
  ]
}
```

This is **JSON**, short for *JavaScript Object Notation*: it started in JavaScript, and now nearly every language and app reads it. Think of boxes inside boxes, each with labeled values:

- `{ }` (read "curly braces") is one box, an object: labels in double quotes, a colon, then the value, with commas between them.
- `[ ]` (read "square brackets") is a list. `stores` is a list of two boxes, one per shop, and each shop's `hours` is a box of its own.
- Text values are in double quotes. Numbers and `true` or `false` aren't.

A file like this, which a program reads to know how to behave, is a **configuration file**.

## Read it: ConvertFrom-Json

`ConvertFrom-Json` turns JSON text into an object. `Get-Content -Raw` reads the file as one piece of text instead of a line at a time, so the converter gets the whole thing at once. Keep the result in a **variable**, a labeled box that holds a value while PowerShell stays open: `$settings` (read "the value of settings"). `=` puts the value in the box. *Variables: $name*, in Module 5, covers them in full.

```powershell
$settings = Get-Content booking-settings.json -Raw | ConvertFrom-Json
$settings.rentalPrices
```

```text
cityBike eBike kidsBike
-------- ----- --------
      12    25        8
```

The first line prints nothing: it fills the box. Then dots reach inside, one box at a time, as with any object's properties. In a list, `[1]` (read "item 1") picks one item, counting from 0:

```powershell
$settings.rentalPrices.eBike
$settings.stores[1].phone
$settings.stores[0].hours.saturday
```

```text
25
555-0178
10:00-16:00
```

Riverside's phone number, and Downtown's Saturday hours. If a file isn't valid JSON, `ConvertFrom-Json` stops with *Conversion from JSON failed with error*, and names the line and position where it got lost: often a missing comma right before it.

## Change a setting

Saving writes over the whole file, so **make a copy first**, as in *Copy and Move: Copy-Item and Move-Item*. If anything goes wrong, the copy puts it right. Then give the e-bike price its new value:

```powershell
Copy-Item booking-settings.json booking-settings.backup.json
$settings.rentalPrices.eBike = 28
$settings.rentalPrices
```

```text
cityBike eBike kidsBike
-------- ----- --------
      12    28        8
```

So far only the object in `$settings` has changed. The file still says 25.

## Save it: ConvertTo-Json and -Depth

`ConvertTo-Json` goes the other way: object in, JSON text out. Try it before saving, to see what it would write:

```powershell
$settings | ConvertTo-Json
```

```text
WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2.
{
  "shopName": "Maple Street Bikes",
  "sendReminders": true,
  "rentalPrices": {
    "cityBike": 12,
    "eBike": 28,
    "kidsBike": 8
  },
  "stores": [
    {
      "name": "Downtown",
      "phone": "555-0142",
      "hours": "@{weekdays=9:00-18:00; saturday=10:00-16:00}"
    },
    {
      "name": "Riverside",
      "phone": "555-0178",
      "hours": "@{weekdays=10:00-18:00; saturday=10:00-17:00}"
    }
  ]
}
```

The price is 28, but look at `hours`. Counting from the outer braces, the stores list is one level in, each shop two, and each shop's hours three. `ConvertTo-Json` goes two levels deep unless you tell it otherwise, and writes anything deeper as text: the opening hours have become one string the website can't read. The warning says so. `-Depth` sets how deep it goes; any number bigger than the file needs is fine, so `-Depth 5` gives room to spare:

![The settings file drawn as boxes inside boxes: the outer settings box holds the stores list at level 1, each shop's box at level 2 and each shop's hours box at level 3. With ConvertTo-Json's default of two levels, the level-3 hours box is squashed into the flat text @{weekdays=9:00-18:00; saturday=10:00-16:00}; with -Depth 5 it stays a box](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/11/190d551c958f43029d635fcbb82bbee9.webp)

```powershell
$settings | ConvertTo-Json -Depth 5 | Set-Content booking-settings.json
(Get-Content booking-settings.json -Raw | ConvertFrom-Json).stores[0].hours
```

```text
weekdays   saturday
--------   --------
9:00-18:00 10:00-16:00
```

The second line reads the saved file back to check it: the hours are still a box of their own, and the e-bike price in the file is now 28. `Set-Content`, from *Writing to Files: Set-Content, Add-Content and >*, did the writing.

**Windows PowerShell 5.1 differs:** it cuts deep levels short in the same way, but with no warning, and it lines its JSON up with extra spaces. On a Mac or Linux, everything here works the same, with `/` in paths.

**Try it.** Turn off the reminder emails: set `sendReminders` to `$false` (read "false"), save with `-Depth 5`, and read the file back. Then put the backup back with `Copy-Item booking-settings.backup.json booking-settings.json`.

## Check yourself

2 questions to try on the lesson page.

## So what

Settings files, website data and app exports are JSON more often than not, and `ConvertFrom-Json` and `ConvertTo-Json -Depth` let you read and change them without breaking a single comma.

## Key terms

- [JSON](https://www.ask-codey.com/glossary/json)
- [ConvertTo-Json](https://www.ask-codey.com/glossary/convertto-json)
- [Configuration File](https://www.ask-codey.com/glossary/configuration-file)

## Cheat sheets

- [JSON: ConvertFrom-Json and ConvertTo-Json](https://www.ask-codey.com/cheat-sheets/powershell-json-cheat-sheet)

## Related

- [Spreadsheets as Objects: Import-Csv](https://www.ask-codey.com/lessons/powershell-import-csv)
- [Properties and Methods](https://www.ask-codey.com/lessons/powershell-properties-and-methods)
- [Copy and Move: Copy-Item and Move-Item](https://www.ask-codey.com/lessons/powershell-copy-and-move)
- [Writing to Files: Set-Content, Add-Content and >](https://www.ask-codey.com/lessons/powershell-writing-to-files)

Source: https://www.ask-codey.com/lessons/powershell-json
