Nesta aula, vamos explorar como o PowerShell pode interagir com a web, realizando requisições HTTP para obter dados, enviar informações e consumir APIs REST. Essa habilidade é essencial para automatizar tarefas que dependem de serviços online, como consultar informações de sistemas, integrar com serviços de terceiros ou até mesmo monitorar a saúde de aplicações.

Dominar requisições web no PowerShell permite que você crie scripts poderosos que se comunicam com o mundo exterior. Veremos dois cmdlets principais: Invoke-WebRequest e Invoke-RestMethod, cada um com suas particularidades. Também abordaremos a autenticação básica para acessar recursos protegidos, um requisito comum em ambientes corporativos.

Invoke-WebRequest

O cmdlet Invoke-WebRequest é a ferramenta mais versátil para interagir com a web no PowerShell. Ele envia uma solicitação HTTP e retorna uma resposta detalhada, incluindo o conteúdo, cabeçalhos, status e outras informações. Isso é útil quando você precisa de controle fino sobre a resposta ou deseja lidar com HTML, imagens ou outros tipos de conteúdo.

A sintaxe básica é simples: Invoke-WebRequest -Uri 'https://exemplo.com'. O resultado é um objeto BasicHtmlWebResponseObject que contém propriedades como Content, StatusCode, Headers e BaseResponse. Vamos ver um exemplo prático:

$resposta = Invoke-WebRequest -Uri 'https://jsonplaceholder.typicode.com/posts/1'
$resposta.StatusCode          # 200
$resposta.Content              # Corpo da resposta (JSON ou HTML)
$resposta.Headers['Content-Type']  # Tipo de conteúdo

Você pode usar parâmetros como -Method para especificar o verbo HTTP (GET, POST, PUT, DELETE), -Headers para enviar cabeçalhos personalizados e -Body para incluir dados no corpo da solicitação. Por exemplo, para fazer um POST com JSON:

$corpo = @{ titulo = 'Novo Post'; conteudo = 'Conteúdo do post' } | ConvertTo-Json
Invoke-WebRequest -Uri 'https://jsonplaceholder.typicode.com/posts' -Method Post -Body $corpo -ContentType 'application/json'

Uma observação importante: Invoke-WebRequest retorna o conteúdo como string. Se você estiver trabalhando com APIs que retornam JSON, pode ser mais conveniente usar Invoke-RestMethod, que já converte automaticamente.

Invoke-RestMethod

O cmdlet Invoke-RestMethod é especializado em consumir APIs REST. Ele envia a requisição e automaticamente converte a resposta JSON (ou XML) em objetos PowerShell, facilitando a manipulação dos dados. Isso elimina a necessidade de converter manualmente o conteúdo com ConvertFrom-Json.

Por exemplo, ao consultar uma API que retorna uma lista de posts, você obtém uma coleção de objetos com propriedades diretamente acessíveis:

$posts = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/posts'
$posts[0].title   # Acessa o título do primeiro post
$posts.Count       # Número de posts

Além disso, Invoke-RestMethod aceita os mesmos parâmetros de Invoke-WebRequest (como -Method, -Headers, -Body), mas o tratamento da resposta é mais amigável. É a escolha ideal para scripts que consomem APIs JSON.

Um exemplo mais completo, incluindo envio de dados:

$novoPost = @{ title = 'PowerShell é demais'; body = 'Aprendendo Invoke-RestMethod'; userId = 1 }
$resultado = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/posts' -Method Post -Body ($novoPost | ConvertTo-Json) -ContentType 'application/json'
$resultado.id   # ID do novo post criado

APIs REST

APIs REST (Representational State Transfer) são um estilo arquitetônico para criar serviços web. Elas usam HTTP e seus verbos (GET, POST, PUT, DELETE) para operações CRUD (Create, Read, Update, Delete). No PowerShell, consumir APIs REST é direto com Invoke-RestMethod.

Vamos entender os principais conceitos:

  • Recursos: São identificados por URLs, por exemplo, https://api.exemplo.com/usuarios.
  • Verbos HTTP: Indicam a ação desejada: GET (ler), POST (criar), PUT (atualizar), DELETE (remover).
  • Status codes: A resposta inclui um código (200 OK, 201 Created, 404 Not Found, 500 Internal Server Error).
  • JSON/XML: Geralmente, os dados são trocados nesses formatos.

Para lidar com APIs que exigem parâmetros na URL (query strings), você pode usar o parâmetro -Body com um dicionário para GET ou simplesmente incluir na URL. Exemplo:

$parametros = @{ userId = 1 }
$posts = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/posts' -Body $parametros
$posts | ForEach-Object { $_.title }

É importante tratar erros: use try/catch para capturar exceções de rede ou respostas com status de erro. O PowerShell lança uma exceção quando o status não é 2xx. Você pode inspecionar $_.Exception.Response.StatusCode para obter o código.

try {
    $dados = Invoke-RestMethod -Uri 'https://api.exemplo.com/recurso'
} catch {
    Write-Host "Erro: $($_.Exception.Message)"
    if ($_.Exception.Response) {
        Write-Host "Status: $($_.Exception.Response.StatusCode)"
    }
}

Autenticação básica

Muitas APIs exigem autenticação. A autenticação básica (Basic Auth) é um método simples em que o cliente envia o nome de usuário e senha codificados em Base64 no cabeçalho Authorization. No PowerShell, você pode criar o cabeçalho manualmente ou usar o parâmetro -Credential.

Para usar -Credential, você precisa de um objeto PSCredential. Você pode obtê-lo com Get-Credential ou criá-lo diretamente:

$usuario = 'admin'
$senha = '123456'
$credencial = [PSCredential]::new($usuario, ($senha | ConvertTo-SecureString -AsPlainText -Force))
Invoke-RestMethod -Uri 'https://api.exemplo.com/dados' -Credential $credencial

Internamente, o PowerShell converte essas credenciais para o cabeçalho correto. Se você precisar de mais controle, pode montar o cabeçalho manualmente:

$par = "$usuario`:$senha"
$base64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($par))
$headers = @{ Authorization = "Basic $base64" }
Invoke-RestMethod -Uri 'https://api.exemplo.com/dados' -Headers $headers

É crucial nunca armazenar senhas em texto plano nos scripts. Prefira usar Get-Credential para solicitar interativamente ou gerenciar segredos com o módulo Microsoft.PowerShell.SecretManagement.

Boas práticas e observações finais

Ao trabalhar com requisições web, siga estas boas práticas:

  • Sempre valide os parâmetros e a URL para evitar injeção de comandos.
  • Use try/catch para tratamento de erros robusto.
  • Prefira Invoke-RestMethod para APIs JSON, pois simplifica o código.
  • Respeite os limites de taxa das APIs e implemente pausas quando necessário.
  • Nunca exponha credenciais em logs ou saídas de script.

Referências

Exercícios

  1. Exercício 1: Use Invoke-WebRequest para baixar o conteúdo da página https://example.com e exiba o status code e o tamanho do conteúdo.
  2. ✓ Resposta:
    $resposta = Invoke-WebRequest -Uri 'https://example.com'
    Write-Host "Status: $($resposta.StatusCode)"
    Write-Host "Tamanho do conteúdo: $($resposta.Content.Length)"
  3. Exercício 2: Consulte a API https://jsonplaceholder.typicode.com/users usando Invoke-RestMethod e liste todos os nomes de usuários.
  4. ✓ Resposta:
    $usuarios = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/users'
    $usuarios | ForEach-Object { $_.name }
  5. Exercício 3: Envie um POST para https://jsonplaceholder.typicode.com/posts com um título e corpo de sua escolha, usando Invoke-RestMethod, e exiba o ID retornado.
  6. ✓ Resposta:
    $post = @{ title = 'Meu primeiro post'; body = 'Conteúdo do post'; userId = 1 }
    $novo = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/posts' -Method Post -Body ($post | ConvertTo-Json) -ContentType 'application/json'
    Write-Host "ID criado: $($novo.id)"
  7. Exercício 4: Implemente autenticação básica manualmente, enviando um cabeçalho Authorization codificado em Base64 para uma URL fictícia (ex.: https://httpbin.org/basic-auth/user/pass). Use usuário 'user' e senha 'pass'.
  8. ✓ Resposta:
    $usuario = 'user'
    $senha = 'pass'
    $par = "$usuario`:$senha"
    $base64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($par))
    $headers = @{ Authorization = "Basic $base64" }
    $resposta = Invoke-RestMethod -Uri 'https://httpbin.org/basic-auth/user/pass' -Headers $headers
    $resposta | ConvertTo-Json
  9. Exercício 5: Escreva um script que faça uma requisição GET para https://jsonplaceholder.typicode.com/posts/1 e trate erros caso a API não esteja acessível.
  10. ✓ Resposta:
    try {
        $post = Invoke-RestMethod -Uri 'https://jsonplaceholder.typicode.com/posts/1'
        Write-Host "Título: $($post.title)"
    } catch {
        Write-Host "Erro na requisição: $($_.Exception.Message)"
        if ($_.Exception.Response) {
            Write-Host "Status code: $($_.Exception.Response.StatusCode)"
        }
    }