JSON (JavaScript Object Notation) tornou-se o formato padrão para troca de dados entre sistemas, especialmente em APIs REST e arquivos de configuração. No PowerShell, o suporte a JSON é nativo, permitindo que você converta objetos PowerShell em JSON e vice-versa de forma simples e eficiente. Esta aula explora os cmdlets principais, armadilhas comuns e práticas recomendadas para trabalhar com JSON em seus scripts.

Dominar JSON no PowerShell é essencial para automatizar integrações com serviços web, gerenciar configurações de aplicações e manipular dados estruturados. Vamos começar entendendo os dois cmdlets fundamentais: ConvertTo-Json e ConvertFrom-Json.

ConvertTo-Json e ConvertFrom-Json

O cmdlet ConvertTo-Json serializa um objeto PowerShell em uma string JSON. Ele aceita qualquer objeto, incluindo arrays, hashtables e objetos personalizados. Por outro lado, ConvertFrom-Json desserializa uma string JSON em um objeto PowerShell, geralmente um PSCustomObject ou array de PSCustomObjects. Esses cmdlets são a ponte entre o mundo PowerShell e o mundo JSON.

Vamos ver um exemplo básico: criar um objeto, convertê-lo para JSON e depois convertê-lo de volta.

# Criando um objeto simples
$pessoa = [PSCustomObject]@{
    Nome = "João"
    Idade = 30
    Ativo = $true
}

# Convertendo para JSON
$json = $pessoa | ConvertTo-Json
Write-Host $json

# Convertendo de volta para objeto
$objeto = $json | ConvertFrom-Json
$objeto.Nome
$objeto.Idade
$objeto.Ativo

A saída do ConvertTo-Json será uma string JSON com as propriedades do objeto. Note que o PowerShell converte automaticamente tipos como booleanos e números. Ao converter de volta, obtemos um PSCustomObject com as mesmas propriedades, mas os valores são tipados conforme o JSON (por exemplo, números viram Int32 ou Double).

Uma característica importante é que o ConvertTo-Json por padrão tenta serializar todas as propriedades, mas objetos com referências circulares ou métodos podem causar erros. Além disso, o cmdlet tem um parâmetro -Compress para remover espaços em branco, útil para reduzir o tamanho da string.

Profundidade

O parâmetro -Depth controla quantos níveis de objetos aninhados o ConvertTo-Json serializa. O valor padrão é 2. Isso significa que se você tiver um objeto com propriedades que são objetos, e esses objetos tiverem outras propriedades, apenas até 2 níveis serão convertidos. Além disso, se a profundidade for excedida, o PowerShell pode truncar os dados ou gerar erros.

Por exemplo, considere um objeto com uma propriedade que é um array de objetos:

$pedido = [PSCustomObject]@{
    Numero = 123
    Itens = @(
        [PSCustomObject]@{ Produto = "Caneta"; Quantidade = 2 },
        [PSCustomObject]@{ Produto = "Caderno"; Quantidade = 1 }
    )
}

# Sem especificar profundidade (padrão 2)
$json = $pedido | ConvertTo-Json
Write-Host $json

# Com profundidade 3
$jsonProfundo = $pedido | ConvertTo-Json -Depth 3
Write-Host $jsonProfundo

No primeiro caso, o JSON gerado terá apenas o primeiro nível de Itens, mas as propriedades internas dos itens podem não ser totalmente serializadas se excederem a profundidade. No segundo caso, com -Depth 3, todos os níveis são incluídos. É importante ajustar a profundidade conforme a complexidade dos seus dados.

Se você não souber a profundidade necessária, pode usar um valor alto como 10, mas cuidado com objetos muito profundos que podem consumir muita memória.

Objetos aninhados

Objetos aninhados são estruturas onde uma propriedade contém outro objeto ou array de objetos. No PowerShell, você pode criar essas estruturas facilmente usando PSCustomObject e hashtables. Ao converter para JSON, a estrutura é preservada, desde que a profundidade seja suficiente.

Vamos criar um exemplo mais complexo: uma empresa com departamentos e funcionários.

$empresa = [PSCustomObject]@{
    Nome = "TechCorp"
    Departamentos = @(
        [PSCustomObject]@{
            Nome = "TI"
            Funcionarios = @(
                [PSCustomObject]@{ Nome = "Ana"; Cargo = "Dev" },
                [PSCustomObject]@{ Nome = "Bruno"; Cargo = "SysAdmin" }
            )
        },
        [PSCustomObject]@{
            Nome = "RH"
            Funcionarios = @(
                [PSCustomObject]@{ Nome = "Carla"; Cargo = "Recruiter" }
            )
        }
    )
}

# Converter para JSON com profundidade 4
$json = $empresa | ConvertTo-Json -Depth 4
Write-Host $json

# Converter de volta
$empresaObj = $json | ConvertFrom-Json
$empresaObj.Departamentos[0].Funcionarios[0].Nome

Para acessar os dados após a desserialização, você utiliza a notação de ponto, como faria com qualquer objeto. Note que arrays aninhados são acessados por índice.

Uma dica: ao receber JSON de APIs, muitas vezes você precisa explorar a estrutura. Você pode usar Get-Member para inspecionar as propriedades do objeto resultante.

APIs

Uma das aplicações mais comuns do JSON no PowerShell é consumir APIs REST. O cmdlet Invoke-RestMethod automaticamente desserializa a resposta JSON em objetos PowerShell, e Invoke-WebRequest retorna o conteúdo bruto que você pode converter manualmente. Vamos ver como fazer uma requisição GET e POST com JSON.

Exemplo de GET:

# Fazendo uma requisição GET para uma API pública
$response = Invoke-RestMethod -Uri "https://jsonplaceholder.typicode.com/posts/1" -Method Get
$response | ConvertTo-Json  # Mostra o objeto como JSON

# Acessando propriedades
$response.title
$response.userId

Para enviar dados via POST, você precisa serializar um objeto em JSON e enviar no corpo da requisição:

$novoPost = [PSCustomObject]@{
    userId = 1
    title = "Meu post"
    body = "Conteúdo do post"
}

$json = $novoPost | ConvertTo-Json

$response = Invoke-RestMethod -Uri "https://jsonplaceholder.typicode.com/posts" -Method Post -Body $json -ContentType "application/json"

$response.id  # O ID criado pela API

É importante definir o ContentType como "application/json" para que o servidor interprete o corpo corretamente. Além disso, algumas APIs exigem autenticação via cabeçalhos, que você pode adicionar com o parâmetro -Headers.

Ao trabalhar com APIs, sempre trate erros de rede e HTTP. Use try/catch e verifique o status code da resposta.

Boas práticas e observações finais

Ao trabalhar com JSON no PowerShell, mantenha estas práticas em mente:

  • Sempre especifique -Depth quando tiver objetos aninhados, para evitar dados truncados.
  • Use -Compress ao enviar dados para reduzir o tamanho da payload.
  • Valide o JSON recebido antes de usar, especialmente se vier de fontes externas.
  • Considere usar classes PowerShell (class) para criar objetos com propriedades tipadas, facilitando a serialização.
  • Para APIs, prefira Invoke-RestMethod, pois ele já converte JSON automaticamente.

Com essas ferramentas, você pode integrar o PowerShell com qualquer serviço que use JSON, desde APIs de terceiros até arquivos de configuração.

Referências

Exercícios

  1. Escreva um script que crie um objeto representando um livro (título, autor, ano) e o converta para JSON, exibindo o resultado.

    ✓ Resposta:
    $livro = [PSCustomObject]@{
        Titulo = "O Senhor dos Anéis"
        Autor = "J.R.R. Tolkien"
        Ano = 1954
    }
    $livro | ConvertTo-Json
  2. Dado o JSON a seguir, converta-o em um objeto PowerShell e imprima o nome do segundo item da lista.

    $json = '{"itens":[{"nome":"item1"},{"nome":"item2"}]}'

    ✓ Resposta:
    $obj = $json | ConvertFrom-Json
    $obj.itens[1].nome
  3. Explique o que acontece se você usar ConvertTo-Json em um objeto com profundidade maior que o valor padrão, sem especificar -Depth. Dê um exemplo.

    ✓ Resposta: O padrão é -Depth 2. Se o objeto tiver mais níveis, eles serão omitidos ou substituídos por valores vazios. Por exemplo, um objeto com uma propriedade que é um objeto com outra propriedade objeto terá o último nível não serializado. Exemplo:
    $obj = [PSCustomObject]@{ a = [PSCustomObject]@{ b = [PSCustomObject]@{ c = 1 } } }
    $obj | ConvertTo-Json  # Resulta em {"a":{"b":{}}}
  4. Faça uma requisição GET para a API pública https://api.github.com/repos/PowerShell/PowerShell e exiba o nome do repositório e a descrição.

    ✓ Resposta:
    $repo = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/PowerShell" -Method Get
    $repo.name
    $repo.description
  5. Crie um script que envie um POST para https://jsonplaceholder.typicode.com/posts com um título e corpo, e imprima o ID retornado.

    ✓ Resposta:
    $post = [PSCustomObject]@{ title = "Meu post"; body = "Conteúdo" }
    $json = $post | ConvertTo-Json
    $response = Invoke-RestMethod -Uri "https://jsonplaceholder.typicode.com/posts" -Method Post -Body $json -ContentType "application/json"
    $response.id