Configurar proxy no PowerShell: Invoke-WebRequest com proxy

Publicado:

16 min de leitura

Acar Diveroli
Autor: Acar Diveroli
Linha Invoke-WebRequest -Proxy com cursor azul, rastro da requisição pelo proxy, StatusCode : 200 e selo de IP de saída

Um script que rodava sem problemas no seu notebook vai para um servidor, ou agora precisa ler uma lista de preços como um visitante de outro país, e cada chamada de Invoke-WebRequest tem que sair por um proxy. O PowerShell tem os parâmetros para isso. Só que eles se comportam de forma diferente no Windows PowerShell 5.1 e no PowerShell 7, e o atalho mais comum, escrever user:pass@ dentro do endereço do proxy, falha com um 407 no 5.1 sem dizer por quê.

Este artigo cobre -Proxy e -ProxyCredential, credenciais sem janela de senha, um proxy para todas as chamadas, variáveis de ambiente e o proxy do sistema do Windows, SOCKS5, um script de download com novas tentativas e os textos exatos dos erros. Cada trecho para o 5.1 foi executado no Windows PowerShell 5.1 (build 26100) contra um proxy local que exige usuário e senha. O PowerShell 7 não estava instalado na máquina de teste, então o comportamento dele vem da documentação da Microsoft e está marcado como tal.

Windows PowerShell 5.1 ou PowerShell 7: por que isso importa?

As duas versões enviam requisições web por pilhas HTTP diferentes, então a mesma configuração de proxy pode funcionar em uma e ser ignorada na outra. O Windows PowerShell 5.1 vem com o Windows e usa a classe HttpWebRequest do .NET Framework; o PowerShell 7 é um download separado e usa HttpClient. $PSVersionTable.PSVersion diz em qual deles um script está rodando.

ComportamentoWindows PowerShell 5.1PowerShell 7.x
-Proxy, -ProxyCredentialSimSim
HTTP_PROXY, HTTPS_PROXY, NO_PROXYIgnoradasLidas desde o 7.0
Proxy quando nenhum é informadoOpções da Internet do usuárioVariáveis, depois as configurações do usuário
Opção -NoProxyNãoDesde o 6.0
Endereço SOCKS5Não7.2 em diante
Aliases curl e wgetApontam para Invoke-WebRequestRemovidos
Novas tentativas integradasNão-MaximumRetryCount

A coluna do 5.1 é o que observamos; a do 7.x segue a referência do Invoke-WebRequest para o PowerShell 7.5.

Como o Invoke-WebRequest envia uma requisição pelo proxy?

  1. O PowerShell resolve o nome do host do proxy, não o do destino, e abre uma conexão TCP com a porta do proxy.
  2. Para um destino http://, ele envia a URL inteira ao proxy (GET http://httpbin.org/ip HTTP/1.1). O proxy busca a página e a repassa, então consegue ler a requisição.
  3. Para um destino https://, ele envia CONNECT httpbin.org:443. Depois que o proxy responde 200 Connection Established, o handshake TLS com o site acontece dentro desse túnel; o proxy vê apenas o nome do host e a porta.
  4. As credenciais só saem depois de um desafio. A primeira tentativa não leva o cabeçalho Proxy-Authorization, o proxy responde 407 com Proxy-Authenticate: Basic e o .NET repete a requisição com o cabeçalho. O código de status 407 e o desafio estão definidos na RFC 9110; o 5.1 não se autentica de antemão, por isso o nosso proxy de teste registrou cada chamada bem-sucedida como este par:
text
11:02:56 407 GET http://httpbin.org/ip (no Proxy-Authorization)
11:02:56 GET http://httpbin.org/ip user=user
  1. O destino responde ao IP de saída do proxy. O cmdlet devolve um objeto com StatusCode, Headers e Content; no 5.1, um status fora de 2xx vira um erro de encerramento.

Como usar o Invoke-WebRequest com proxy?

Crie um objeto de credenciais e passe ao cmdlet o endereço do proxy e o objeto:

powershell
$pass = ConvertTo-SecureString "pass" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("user", $pass)

$r = Invoke-WebRequest -UseBasicParsing -Uri "https://httpbin.org/ip" `
    -Proxy "http://pr.proxynet.io:8000" -ProxyCredential $cred
$r | Select-Object StatusCode, StatusDescription | Format-List
$r.Content
text
StatusCode        : 200
StatusDescription : OK

{
  "origin": "203.0.113.42"
}

O httpbin.org/ip devolve o endereço de onde a requisição veio, então um proxy que funciona mostra ali o IP de saída dele, e não o seu. O valor de -Proxy é um URI e mantém o esquema http:// mesmo com destinos HTTPS: ele descreve a conexão com o proxy, enquanto a página continua criptografada dentro do túnel CONNECT. Os dois parâmetros estão documentados na página do Invoke-WebRequest para o Windows PowerShell 5.1.

Sempre adicione -UseBasicParsing no 5.1. Sem ele, o cmdlet analisa o HTML com o motor do Internet Explorer e, desde a atualização de segurança da Microsoft de dezembro de 2025 para a CVE-2025-54100, pede confirmação antes, algo que um script agendado não consegue responder. Na nossa execução, uma chamada sem a opção falhou com Object reference not set to an instance of an object. O PowerShell 7 só faz análise básica e ignora a opção.

O Invoke-RestMethod aceita os mesmos parâmetros de proxy e devolve JSON já interpretado em vez de um objeto de resposta:

powershell
$ip = Invoke-RestMethod -Uri "https://api.ipify.org?format=json" `
    -Proxy "http://pr.proxynet.io:8000" -ProxyCredential $cred
$ip.ip

Nos produtos residencial e móvel da Proxynet, o nome de usuário carrega o país, a cidade e a sessão escolhidos no Gerador de endpoints do painel, então o comando continua o mesmo seja qual for a saída que você escolher.

Como informar as credenciais do proxy?

A senha do proxy viaja em um objeto PSCredential, nunca dentro do endereço. O Get-Credential pede a senha de forma interativa; um script a monta a partir de uma string segura, como acima. A página da Microsoft sobre o ConvertTo-SecureString avisa que uma senha em texto puro na linha de comando vai parar nos logs de eventos e no histórico de comandos, então leia-a de uma variável de ambiente ou de um cofre de segredos:

powershell
$pass = ConvertTo-SecureString $env:PROXY_PASS -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($env:PROXY_USER, $pass)

Três detalhes dos nossos testes:

  • user:pass@ dentro de -Proxy é ignorado no 5.1. -Proxy "http://user:pass@pr.proxynet.io:8000" sem -ProxyCredential terminou com (407) Proxy Authentication Required; o log do proxy não mostrou nenhuma credencial chegando.
  • Caracteres especiais não precisam de codificação. Uma senha p@ss:w#rd passou sem alterações pelo PSCredential, enquanto a forma de URL precisaria de %40, %3A e %23.
  • Uma sessão web mantém o proxy. Depois de -Proxy ... -SessionVariable s, uma segunda chamada só com -WebSession $s passou de novo pelo proxy; o objeto de sessão guarda o proxy ao lado dos cookies.

O -ProxyUseDefaultCredentials envia, em vez disso, a conta do Windows do usuário atual, para proxies corporativos que autenticam contra o domínio; a documentação diz que ele não pode ser combinado com -ProxyCredential. Não testamos aqui: o nosso proxy só fala Basic.

A senha desaparece por completo quando o IP da máquina está autorizado no painel do proxy: -Proxy "http://pr.proxynet.io:8000" passa a ser a configuração inteira. A Proxynet aceita até 10 IPs na whitelist, o que combina com tarefas agendadas em um servidor de endereço fixo.

Como definir o proxy para todos os comandos?

$PSDefaultParameterValues é uma tabela hash de chaves Cmdlet:Parâmetro que o PowerShell aplica sempre que você omite o parâmetro. Duas entradas por cmdlet bastam:

powershell
$PSDefaultParameterValues["Invoke-WebRequest:Proxy"] = "http://pr.proxynet.io:8000"
$PSDefaultParameterValues["Invoke-WebRequest:ProxyCredential"] = $cred
$PSDefaultParameterValues["Invoke-RestMethod:Proxy"] = "http://pr.proxynet.io:8000"
$PSDefaultParameterValues["Invoke-RestMethod:ProxyCredential"] = $cred

Invoke-RestMethod -Uri "https://api.ipify.org?format=json"   # passa pelo proxy

As chaves aceitam curingas, então "Invoke-*:Proxy" cobre os dois cmdlets em uma linha; as duas formas funcionaram no nosso teste. A tabela fica vazia em cada sessão nova, a menos que as linhas estejam no $PROFILE, e um script que roda com outra conta nunca vê o seu perfil, então deixe os parâmetros explícitos em tudo o que você entregar.

Sobrescrever com -Proxy $null em uma chamada direta falha com The cmdlet cannot run because the following parameter is missing: Proxy enquanto existir um padrão para ProxyCredential. Em vez disso, desative a tabela por um instante: $PSDefaultParameterValues["Disabled"] = $true, execute a chamada e volte o valor para $false. No nosso teste, a chamada com Disabled saiu direto e a seguinte passou de novo pelo proxy.

O PowerShell lê HTTP_PROXY e HTTPS_PROXY?

O Windows PowerShell 5.1 não lê. Com $env:HTTP_PROXY e $env:HTTPS_PROXY definidas e sem o parâmetro -Proxy, a nossa requisição foi direto ao destino; o proxy nunca a viu. O curl.exe, o git e o pip na mesma máquina seguem essas variáveis, daí a confusão.

O PowerShell 7 lê, segundo a documentação: desde o 7.0, os cmdlets pegam o proxy padrão do HttpClient.DefaultProxy do .NET, que no Windows lê primeiro HTTP_PROXY, HTTPS_PROXY, ALL_PROXY e a lista de exceções NO_PROXY e recorre às configurações de proxy do usuário quando as variáveis estão vazias.

powershell
# Apenas no PowerShell 7; o 5.1 ignora isso
$env:HTTPS_PROXY = "http://pr.proxynet.io:8000"
$env:NO_PROXY = "localhost,127.0.0.1,.internal.example"
Invoke-WebRequest -Uri "https://httpbin.org/ip"            # pelo proxy
Invoke-WebRequest -Uri "https://httpbin.org/ip" -NoProxy   # direto, apenas esta chamada

As credenciais continuam em -ProxyCredential, por chamada ou por meio de $PSDefaultParameterValues, exatamente como no 5.1.

E o proxy do sistema do Windows e o netsh winhttp?

Sem -Proxy, o 5.1 recorre ao proxy das Opções da Internet do usuário atual, a configuração que o Windows mostra em Configurações, Rede e Internet, Proxy. A documentação do .NET Framework diz que o WebRequest.DefaultWebProxy lê primeiro o arquivo de configuração do aplicativo e, se ele não existir, o proxy das Opções da Internet do usuário. Um script que de repente sai por um proxy inesperado normalmente está seguindo essa configuração; Configuração de proxy no Windows e no Chrome mostra onde ela fica.

O Windows mantém um segundo registro de proxy para o WinHTTP, a biblioteca HTTP usada por serviços e componentes do sistema. Ele é gerenciado com netsh winhttp e não afeta os cmdlets do PowerShell, que usam o .NET. Os comandos abaixo vêm da referência do netsh da Microsoft e não foram executados aqui, porque mudam uma configuração da máquina inteira:

text
netsh winhttp show proxy
netsh winhttp set proxy proxy-server="pr.proxynet.io:8000" bypass-list="*.internal.example"
netsh winhttp import proxy source=ie
netsh winhttp reset proxy

O set proxy aceita um servidor e uma lista de exceções separada por ponto e vírgula, e nada mais, então um proxy que pede usuário e senha é mais bem configurado por script com -ProxyCredential, ou deixado sem senha com uma whitelist de IP.

Como usar o proxy a partir de classes .NET em um script?

Scripts que chamam System.Net.WebClient ou HttpWebRequest diretamente não enxergam -Proxy; eles leem o WebRequest.DefaultWebProxy, que vale para o processo inteiro. Defini-lo uma vez faz essas classes e, no 5.1, cada Invoke-WebRequest sem o próprio -Proxy passarem pelo proxy:

powershell
$proxy = New-Object System.Net.WebProxy("http://pr.proxynet.io:8000")
$proxy.Credentials = New-Object System.Net.NetworkCredential("user", "pass")
$proxy.BypassList = @("^http://intranet\.example\.")
[System.Net.WebRequest]::DefaultWebProxy = $proxy

(New-Object System.Net.WebClient).DownloadString("https://api.ipify.org")

A configuração vive só naquele processo do PowerShell. O BypassList guarda expressões regulares comparadas com a URL completa; no nosso teste, o padrão da intranet foi excluído do proxy e o host público não.

Uma regra do WebProxy nos custou uma hora: requisições para localhost ou 127.0.0.1 nunca usam proxy. O IsBypassed devolveu True para os dois mesmo com BypassProxyOnLocal em False, então todo teste contra um servidor web local saiu direto e parecia que o proxy funcionava. Teste contra um endereço público ou dê ao servidor local um nome de host com um ponto.

O Invoke-WebRequest aceita SOCKS5?

No Windows PowerShell 5.1, não. -Proxy "socks5://pr.proxynet.io:1080" para com The ServicePointManager does not support proxies with the socks5 scheme., e um endereço de proxy https:// falha do mesmo jeito, então o 5.1 só fala com proxies por HTTP simples.

O PowerShell 7.2 e versões mais novas rodam sobre o .NET 6 ou mais recente, e o anúncio de rede do .NET 6 da Microsoft documenta o suporte a SOCKS4, SOCKS4a e SOCKS5 no HttpClient por meio de um endereço de proxy socks5://. A referência do cmdlet não menciona SOCKS e não pudemos rodar o 7 aqui, então trate -Proxy "socks5://pr.proxynet.io:1080" como algo a verificar na sua versão.

No 5.1, o caminho prático é o cURL de verdade que vem com o Windows 10 e 11: curl.exe -x "socks5h://user:pass@pr.proxynet.io:1080" https://httpbin.org/ip, com socks5h para que o proxy resolva o nome do host. As opções estão explicadas em cURL com proxy; no lugar de 1080, use a porta SOCKS5 que o seu Gerador de endpoints mostra.

Exemplo: baixar uma lista de URLs pelo proxy com novas tentativas

O script baixa uma lista de URLs pelo proxy, tenta de novo as falhas temporárias com uma pausa crescente, para na hora diante de um 407 e imprime uma linha por URL. Ele só precisa do Windows PowerShell 5.1:

powershell
# fetch.ps1: cada URL da lista pelo proxy, com novas tentativas
$ErrorActionPreference = "Stop"
$ProxyUri = "http://pr.proxynet.io:8000"
$ProxyCred = New-Object System.Management.Automation.PSCredential (
    "user", (ConvertTo-SecureString "pass" -AsPlainText -Force))

$urls = @(
    "https://httpbin.org/ip",
    "https://httpbin.org/status/503",
    "https://httpbin.org/status/404",
    "https://httpbin.org/headers"
)
$retryCodes = 408, 429, 500, 502, 503, 504

function Get-WithRetry {
    param([string]$Url, [int]$Attempts = 4)
    for ($i = 1; $i -le $Attempts; $i++) {
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        try {
            $r = Invoke-WebRequest -UseBasicParsing -Uri $Url -Proxy $ProxyUri -ProxyCredential $ProxyCred -TimeoutSec 30
            return [pscustomobject]@{ Url = $Url; Status = $r.StatusCode; Attempts = $i; Ms = $sw.ElapsedMilliseconds; Bytes = $r.RawContentLength }
        } catch [System.Net.WebException] {
            $code = 0
            if ($_.Exception.Response) { $code = [int]$_.Exception.Response.StatusCode }
            if ($code -eq 407) { throw "Proxy refused the credentials (407). Check user:pass or the IP whitelist." }
            if (($code -in $retryCodes -or $code -eq 0) -and $i -lt $Attempts) {
                $wait = [math]::Pow(2, $i - 1)   # 1, 2, 4 segundos
                Write-Warning "$Url -> $code ($($_.Exception.Status)); retry $i in $wait s"
                Start-Sleep -Seconds $wait
                continue
            }
            return [pscustomobject]@{ Url = $Url; Status = $code; Attempts = $i; Ms = $sw.ElapsedMilliseconds; Bytes = 0 }
        }
    }
}

$results = foreach ($u in $urls) { Get-WithRetry -Url $u }
$results | Format-Table -AutoSize

Na nossa execução, o endereço /status/503 respondeu 503 duas vezes, foi tentado de novo depois de 1 e 2 segundos e deu certo na terceira tentativa porque o servidor de teste se recupera; o 404 voltou sem nova tentativa:

text
WARNING: https://httpbin.org/status/503 -> 503 (ProtocolError); retry 1 in 1 s
WARNING: https://httpbin.org/status/503 -> 503 (ProtocolError); retry 2 in 2 s

Url                            Status Attempts Ms Bytes
---                            ------ -------- -- -----
https://httpbin.org/ip            200        1 34    55
https://httpbin.org/status/503    200        3 11    65
https://httpbin.org/status/404    404        1  3     0
https://httpbin.org/headers       200        1 10   250

Três escolhas importam. $_.Exception.Response.StatusCode é o único lugar em que o 5.1 expõe o status de uma requisição que falhou, porque um 4xx ou 5xx é lançado como erro em vez de devolvido. Um $code igual a 0 significa que não houve resposta nenhuma, como em um tempo limite esgotado, e também é tentado de novo. -TimeoutSec 30 limita cada tentativa; o padrão, 0, espera para sempre. O PowerShell 7 traz -MaximumRetryCount 3 -RetryIntervalSec 2 embutido, e a documentação diz que um 429 com Retry-After se sobrepõe a esse intervalo.

Cada Invoke-WebRequest abre a própria conexão com o proxy, então um gateway rotativo entrega a cada chamada um IP de saída diferente. Um login seguido de várias páginas precisa do contrário: uma sessão fixa no nome de usuário mantém o mesmo IP por 1 a 60 minutos nos Proxies residenciais, enquanto -SessionVariable mantém os cookies do seu lado.

Onde os scripts de proxy do PowerShell aparecem?

As tarefas agendadas são o lugar de sempre: uma tarefa noturna confere o preço e o estoque dos seus próprios anúncios como um comprador de outro país os vê, um script de monitoramento requisita o seu site de várias regiões e avisa quando a moeda ou o idioma estão errados, um agente de build atrás de um proxy corporativo instala módulos por ele. Uma API de parceiro que libera um único endereço é acessada de uma tarefa cuja saída nunca muda; os Proxies ISP dão a essa tarefa um IP dedicado que sobrevive a reinicializações.

Erros comuns de proxy no PowerShell e como corrigir

As mensagens aparecem como o Windows PowerShell 5.1 as imprime com a interface em inglês; em um Windows em português ou em alemão, a parte .NET do texto é traduzida.

  • The remote server returned an error: (407) Proxy Authentication Required. Falta -ProxyCredential, as credenciais estão dentro do endereço, a senha está errada ou o IP não está na whitelist. $_.Exception.Response.StatusCode.value__ dá 407 em um bloco catch; as causas estão reunidas em Como corrigir HTTP 407 Proxy Authentication Required.
  • Unable to connect to the remote server com Status : ConnectFailure. Porta do proxy errada, um firewall no meio ou o proxy está fora do ar.
  • The proxy name could not be resolved: 'pr.proxynet.io'. Um erro de digitação no nome do host ou DNS indisponível; a mensagem cita o proxy, não o destino.
  • The operation has timed out. O -TimeoutSec é menor do que o proxy e o destino precisam; o nosso limite de 2 segundos contra uma página de 5 segundos produziu essa mensagem.
  • The ServicePointManager does not support proxies with the socks5 scheme. Um endereço de proxy socks5:// ou https:// no 5.1; use http://, o PowerShell 7.2+ ou o curl.exe.
  • A parameter cannot be found that matches parameter name 'x'. Um comando do cURL digitado no 5.1, onde curl é um alias do Invoke-WebRequest; escreva curl.exe.
  • Object reference not set to an instance of an object. Uma chamada do 5.1 sem -UseBasicParsing em um script.
  • The cmdlet cannot run because the following parameter is missing: Proxy. -Proxy $null enquanto o $PSDefaultParameterValues ainda guarda um ProxyCredential; use a chave Disabled no lugar.
  • O proxy é pulado em silêncio. O destino é localhost ou 127.0.0.1, ou o script confia no HTTPS_PROXY no 5.1. Compare o api.ipify.org com e sem -Proxy.

Guia de decisão

NecessidadeRecomendação
Um comando pelo proxy-Proxy mais -ProxyCredential
Todos os comandos de uma sessão$PSDefaultParameterValues no $PROFILE
Nenhuma senha no scriptWhitelist de IP no painel, só -Proxy
Proxy corporativo com login do Windows-ProxyUseDefaultCredentials
Uma chamada sem o proxy-NoProxy (7) ou a chave Disabled (5.1)
SOCKS5PowerShell 7.2+, ou curl.exe com socks5h://
Código com WebClient ou HttpWebRequest[System.Net.WebRequest]::DefaultWebProxy
O mesmo IP de saída em um fluxo de loginSessão fixa no nome de usuário
Serviços e Windows Updatenetsh winhttp set proxy

Perguntas frequentes

Como configurar um proxy para o Invoke-WebRequest?

Adicione -Proxy "http://host:port" e, se o proxy pedir senha, -ProxyCredential com um objeto PSCredential. Os mesmos dois parâmetros existem no Invoke-RestMethod e, segundo a documentação do PowerShellGet 2.x, no Install-Module.

Por que o Invoke-WebRequest devolve 407 Proxy Authentication Required?

Porque o proxy não recebeu credenciais utilizáveis. No 5.1, isso acontece quando o usuário e a senha são escritos no endereço em vez de em -ProxyCredential, quando a senha está errada ou quando o proxy espera o seu IP em uma whitelist e o endereço da máquina mudou.

O Invoke-WebRequest usa as configurações de proxy do Windows?

Sim, quando você não informa -Proxy. O Windows PowerShell 5.1 pega o proxy das Opções da Internet do usuário atual; o PowerShell 7 lê primeiro HTTP_PROXY e HTTPS_PROXY e recorre às configurações do usuário. O proxy do WinHTTP definido com netsh winhttp é um registro separado e nenhum dos dois o lê.

Como ignorar o proxy em uma única requisição no PowerShell?

No PowerShell 7, adicione -NoProxy a essa chamada. No 5.1, deixe o -Proxy de fora; se o $PSDefaultParameterValues o adicionar mesmo assim, coloque $PSDefaultParameterValues["Disabled"] = $true em volta da chamada. Para hosts inteiros, use NO_PROXY no 7 ou um BypassList em um objeto WebProxy no 5.1.

Dá para usar um proxy SOCKS5 com o Invoke-WebRequest?

No Windows PowerShell 5.1, não: ele rejeita o esquema socks5://. O PowerShell 7.2 e versões mais novas rodam sobre o .NET 6+, que suporta proxies SOCKS5 no HttpClient; verifique na sua versão. No 5.1, chame o curl.exe com socks5h:// no lugar.

Como verificar se o PowerShell está mesmo usando o proxy?

Requisite https://api.ipify.org uma vez sem e uma vez com -Proxy: dois endereços diferentes, o segundo no país do proxy, significam que o proxy está em uso. O mesmo endereço duas vezes significa que a chamada saiu direto, quase sempre porque o destino era localhost ou porque o 5.1 ignorou as variáveis que você definiu.

Em resumo

Passe o proxy ao Invoke-WebRequest e ao Invoke-RestMethod com -Proxy e um PSCredential em -ProxyCredential, nunca dentro do endereço; defina os dois uma vez em $PSDefaultParameterValues quando todas as chamadas devem usá-lo. O Windows PowerShell 5.1 ignora HTTP_PROXY, recorre às Opções da Internet, deixa os endereços de loopback fora do proxy e não fala SOCKS5; o PowerShell 7 lê as variáveis, acrescenta -NoProxy e novas tentativas e aceita SOCKS5 a partir do 7.2. Mantenha -UseBasicParsing e -TimeoutSec em todo script do 5.1 e teste contra um endereço público. Os endpoints que aceitam exatamente esses parâmetros estão na página de proxies da Proxynet.