# PowerShell 5.1 fixes for a JSON API

I still use Windows PowerShell 5.1 for my personal research scripts, mostly because it's already on every machine I touch. When I added Instagram lookups through HikerAPI, the API itself was the easy part: one `x-access-key` header and plain JSON back. The work was in three small helpers that made the responses behave in 5.1. None of them is specific to HikerAPI, so here they are.

## 1\. Decode the body as UTF-8 yourself

`Invoke-RestMethod` in 5.1 falls back to ISO-8859-1 when the server doesn't send a charset, and Instagram captions are full of emoji and accented letters. They arrived mangled until I read the raw bytes:

```powershell
function GetJson($url, $headers) {
  $r = Invoke-WebRequest -UseBasicParsing -Uri $url -Headers $headers
  $ms = New-Object IO.MemoryStream; $r.RawContentStream.CopyTo($ms)
  (([Text.Encoding]::UTF8.GetString($ms.ToArray())) | ConvertFrom-Json) | ForEach-Object { $_ }
}
```

The `ForEach-Object { $_ }` at the end is the second fix hiding in there: `ConvertFrom-Json` in 5.1 hands back a JSON array as a single object, so `.Count` and loops quietly misbehave. Piping it through unrolls the list.

## 2\. Read a field by more than one name

Once in a while a field came back with a slightly different name. The one I caught was `1ltaken_at` where I expected `taken_at`. Instead of trusting one exact key, I read fields through a helper that accepts a few candidates and a short prefix:

```powershell
function Campo($o, [string[]]$nomes) {
  if ($null -eq $o) { return $null }
  foreach ($n in $nomes) {
    $p = $o.PSObject.Properties | Where-Object { $_.Name -eq $n -or $_.Name -match ('^\w{0,3}' + [regex]::Escape($n) + '$') } | Select-Object -First 1
    if ($p -and $null -ne $p.Value) { return $p.Value }
  }
  return $null
}
```

`Campo $post 'taken_at'` now finds the value either way, and `Campo $post 'id', 'pk'` covers endpoints that name the same thing differently.

## 3\. Walk nested results instead of guessing the path

Hashtag results come grouped in sections and layouts rather than as a flat list. Rather than hard-coding that shape, I walk the whole object and keep anything that looks like a post:

```powershell
function Midias($o, $acc) {
  if ($null -eq $o -or $o -is [string] -or $o -is [ValueType]) { return }
  if ($o -is [Array]) { foreach ($x in $o) { Midias $x $acc }; return }
  $nomes = $o.PSObject.Properties.Name
  if ($nomes -contains 'code' -and ($nomes -contains 'like_count' -or $nomes -contains 'media_type')) { $acc.Add($o); return }
  foreach ($p in $o.PSObject.Properties) { Midias $p.Value $acc }
}
```

If the layout changes tomorrow, this keeps working as long as a post still looks like a post.

## About the API itself

I'm happy with HikerAPI for this. You get 100 free requests when you sign up. The entry tier is $0.02 per request, and `/sys/balance` is free, so my script prints what each call cost. The quirks above took an afternoon to sort out, and since then it has been the dependable part of the pipeline.

(The helper names are Portuguese because that's what the rest of my scripts use: `Campo` means field and `Midias` means media.)
